Потоки Windows:когда вы должны использовать InterlockedExchangeAdd()?

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

Вопрос

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

Подготовка CRITICAL_SECTION cs КРИТИЧЕСКАЯ СЕКЦИЯ cs;int *p = malloc(sizeof(int));// Сайт размещения Инициализируйте критическую секцию(&cs);// ПОДСКАЗКА для первой записи

Поток №1 { *р = 1;// Первая запись }

Поток №2 { Введите критический раздел (&cs);*р = 2;// Вторая запись Оставить критическую секцию(&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() более полезно?

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

Решение

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

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

Upd:Использование 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::поток.

Другие советы

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

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

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

Убедитесь, что m_bIsTerminated помечен как volatile, и все должно быть в порядке.Хотя мне кажется довольно странным, что вы // еще немного кода после установки значения "is terminated" в true.На что именно указывает эта переменная?

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

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