Потоки Windows: когда следует использовать InterlockedExchangeAdd ()? - PullRequest
0 голосов
/ 15 января 2010

Имена этой функции кажутся сложными. Когда точно известно, что это путь, а не делать что-то вроде этого:

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

Тема # 1 { * р = 1; // Первая запись }

Тема № 2 { EnterCriticalSection (& CS); * р = 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 () более полезным?

Ответы [ 3 ]

3 голосов
/ 15 января 2010

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

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

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

0 голосов
/ 15 января 2010

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

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

Upd: Использование volatile для переменной может работать, однако это не рекомендуется, см. http://www.open -std.org / jtc1 / sc22 / wg21 / docs / paper / 2006 / n2016.html и http://www -949.ibm.com / программное обеспечение / рациональное / кафе / блоги / ccpp-параллельные-многоядерные / теги / c% 2B% 2B0x например.

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

0 голосов
/ 15 января 2010

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

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

...