2010-01-14 3 views
0

Именование этой функции похоже на то, что это сложный процесс. Когда именно можно узнать, что это путь вместо того, чтобы делать что-то вроде этого:Темы Windows: когда вы должны использовать InterlockedExchangeAdd()?

Подготовка CRITICAL_SECTION CS; int * p = malloc (sizeof (int)); // Выделение сайта InitializeCriticalSection (& cs); // ПОДСКАЗКА для первой записи

Thread # 1 { * р = 1; // Первый Написать }

Thread # 2 { EnterCriticalSection (& CS); * p = 2; // Вторая запись LeaveCriticalSection (& cs); }

У меня есть запись, что может быть сделано в одном потоке:

Run() 
{ 
// some code 
m_bIsTerminated = TRUE; 
// some more code 
} 

Тогда у меня есть для чтения, что делается в другом потоке (потенциально в то же время):

Terminate() 
{ 
// some code 
if(m_bIsTerminated) 
{ 
m_dwThreadId = 0; 
m_hThread = NULL; 
m_evExit.SetEvent(); 
return; 
} 
// even more code 
} 

Какое лучшее решение для решения этой гонки? Являются ли критические разделы способ перехода или является использование InterlockedExchangeAdd() более полезным?

ответ

0

InterlockedExchangeAdd используется для добавления значения к целому числу в качестве атомарной операции, что означает, что вам не придется использовать критический раздел. Это также устраняет риск возникновения взаимоблокировки, если один из ваших потоков создает исключение - вам нужно убедиться, что вы не держите какой-либо блокировки, так как это предотвратит получение этой блокировки другими потоками.

Для вашего сценария вы можете определенно использовать функцию блокировки ..., но я бы использовал событие (CreateEvent, SetEvent, WaitForSingleObject), вероятно, потому, что мне часто приходится ждать нескольких объектов (вы можете дождитесь нулевой секунды в вашем сценарии).

Обновление: использование volatile для переменной может работать, однако это не рекомендуется, например: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html и http://www-949.ibm.com/software/rational/cafe/blogs/ccpp-parallel-multicore/tags/c%2B%2B0x.

Если вы хотите быть портативным, взгляните на boost::thread.

+0

Я использую события для обычных событий начала и завершения потока, но это происходит, когда вы хотите завершить работу до того, как поток завершит работу. Я хочу убедиться, что он завершает изящно и помещает поток обратно в пул, поэтому его можно использовать позже, если это необходимо. –

+0

Эти вызовы зависят от Windows. – Omnifarious

+0

@Omnifarious: Поскольку OP упоминает InterlockedExchangeAdd, и вопрос помечен Windows, я думаю, справедливо предположить, что вопрос также зависит от Windows. – villintehaspam

3

В вашем случае нет гонки. Переменная никогда не возвращается обратно в ЛОЖЬ, не так ли? Это просто «прошу умереть» за нить, верно? Тогда нет никакой необходимости в синхронизации.

Семейство функций InterlockedXXX использует атомарные 3-операндовые команды процессора Intel (XADD и CMPXCNG). Поэтому они намного дешевле, чем критический раздел. И тот, который вы хотите для потокобезопасного назначения, - InterlockedCompareExchange().

UPD: и отметьте переменную как изменчивую.

+2

Существует проблема. Значение может находиться в кеше одного ядра, а другое ядро ​​может занять некоторое время, чтобы увидеть обновленное значение. – Omnifarious

+0

Вместо обновления, используйте память после обновления переменной. У этого есть семантика, которую вы действительно хотите (выполнить все записи * сейчас *). Неустойчивость не идеальна, поскольку 1) она не препятствует переупорядочению записей и 2) она заставляет * все * записывать в переменную, которая должна быть немедленно записана, что вам не обязательно нужно. – jalf

0

Убедитесь, что m_bIsTerminated отмечен как изменчивый, и все должно быть в порядке. Хотя мне кажется довольно странным, что вы // еще один код после установки «завершен» на true. Что именно указывает эта переменная?

Ваше «условие гонки» состоит в том, что ваши различные элементы // большего количества кода могут выполняться в разных порядках. Ваша переменная не помогает. Ваша цель - заставить их выполнять детерминированный порядок? Если да, вам понадобится переменная условия, чтобы ждать в одном потоке и установить в другом. Если вы просто не хотите, чтобы они выполнялись одновременно, критический раздел был бы прекрасен.

+0

Это указывает на то, что текущий поток был сигнализирован о завершении, затем возвращает поток обратно в пул, в то время как другие потоки продолжают работать, пока они не будут сигнализированы о завершении. –

+0

В этом примере достаточно летучих, где один поток читает и один поток пишет. –

+0

Вы правы - не имеет значения точный порядок, который другой поток видит в записи, только что он действительно видит это. – Michael