Это использование монитора. Wait / Pulse имеют состояние гонки?

StackOverflow https://stackoverflow.com/questions/2631658

Вопрос

У меня простой продюсер / потребительский сценарий, где есть только один элемент, который производится / потребляется. Кроме того, производитель ждет рабочей нити, чтобы закончить, прежде чем продолжить. Я понимаю, что это избавляет весь смысл многопоточье, но, пожалуйста, просто предположим, что это действительно должно быть таким способом (:

Этот код не скомпилируется, но я надеюсь, что вы получите идею:

// m_data is initially null

// This could be called by any number of producer threads simultaneously
void SetData(object foo)
{
    lock(x)                      // Line A
    {
        assert(m_data == null);
        m_data = foo;
        Monitor.Pulse(x)         // Line B
        while(m_data != null)
            Monitor.Wait(x)      // Line C
    }
}

// This is only ever called by a single worker thread
void UseData()
{
    lock(x)                      // Line D
    {
        while(m_data == null)
            Monitor.Wait(x)      // Line E
        // here, do something with m_data
        m_data = null;
        Monitor.Pulse(x)         // Line F
    }
}

Вот ситуация, которую я не уверен в:

Предположим, что многие потоки вызова SetData () с разными входами. Только один из них попадет в замок, а остальные будут заблокированы на линии A. Предположим, тот, который попал внутри наборов замков m_data. и проходит путь к линии C.

Вопрос: Может ли ожидание () на линии C позволять другую нить в строке A, чтобы получить замок и перезаписать m_data. До того, как рабочая нить даже доходит до него?

Предположим, что не происходит, а рабочая нить обрабатывает оригинал m_data., И в конечном итоге проходит свой путь к линии F, что происходит, когда этот пульс () уходит?

Будет ли только нить в ожидании на линии C, чтобы получить замок? Или это будет соревноваться со всеми другими потоками, ожидающими на линии а также?

По сути, я хочу знать, если импульс () / ждать () взаимодействуют друг с другом специально «под капотом» или если они находятся на одном уровне с блокировкой ().

Решение этих проблем, если они существуют, очевидно, конечно, безусловно - просто Surround SetData () с другим замком - скажем, заблокируйте (y). Мне просто любопытно, если это даже проблема для начала.

Это было полезно?

Решение

Нет никакой гарантии, что потребитель будет трансформируется на очередь ожидания или готовности перед другим производителем.
C # и мониторы стиля Java описаны на Википедия, под «неявным условием мониторов».
Хороший обзор того, что происходит в Monitor (взято из это Отличный сайт):alt text

«Может ли ожидание () на линии C позволить другую нить в строке A для получения блокировки и перезаписи m_data до того, как рабочая нить даже доберется до него?"

Предположим, что SetData() называется двумя потоками производителей, P1. & Счастливый.
Потребительская нить, C1. начинается тоже.
P1., Счастливый и C1. Все введите готовую очередь.
P1. сначала приобретает замок.
Ожидание очередь пуста, Pulse() на line B не имеет эффекта.
P1. ждет line C, Так что он находится на очередь ожидания.
Следующая поток в готовой очереди приобретает замок.
Это может оно может быть Счастливый или C1. - В первом случае утверждение не удается.
У вас есть состояние гонки.

«Предположим, что это не происходит, а рабочая нить обрабатывает оригинал m_data и в конечном итоге проходит путь к линии f, что происходит, когда этот пульс () уходит?»

Это будет переместить официант от очереди ожидания на очередь готовности.
Замок удерживается потоком, которая выдает Pulse().
Уведомленная нить будет получить шанс Чтобы получить блокировку после пульсирующей нити выпускает замок (уже могут быть другие в очереди готовности).
От MSDN, Monitor.pulse ():
«Нить, которая в настоящее время владеет блокировкой на указанном объекте, вызывает этот метод, чтобы сигнализировать следующий поток в строке для блокировки. После получения импульса поток ожидания перемещается в очередь. Когда нить, вызываемый импульс, выделяет блокировку Следующая поток в готовой очереди (которая не обязательно является импульсной резьбой), приобретает замок ».

«Будет ли только нить в ожидании на линии C, чтобы получить замок? Или это будет соревноваться со всеми другими потоками, ожидающими на линии A?»

Все темы, которые находятся на готовой очереди «Compate» для блокировки рядом.
Неважно, если они туда попали прямо или из очереди ожидания с помощью Pulse().

«Очереди» могут быть реализованы другими способами. (Не очередь Структура данных как таковая).
Таким образом А. Monitor Реализация может не гарантировать справедливость - но может иметь более высокую общую пропускную способность / производительность.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top