Следует ли использовать InterlockedExchange для всех настроек переменной?

Я использую InterlockedExchange в Windows, и у меня есть два вопроса, которые вместе составляют мой главный вопрос.

InterlockedExchange использует тип LONG (32 бита). Согласно документации Microsoft Доступ к заблокированным переменным: простые операции чтения и записи в 32-разрядные переменные являются атомарными операциями без InterlockedExchange. Согласно документации функции InterlockedExchange: Эта функция является атомарной по отношению к вызовам других заблокированных функций. Считывание / запись LONG в Windows без взаимосвязанных функций является атомарным или нет?

Я просматриваю код, в котором один поток устанавливает переменную, а затем все дальнейшие обращения к этой переменной этим потоком или любым количеством созданных им потоков используют InterlockedExchange. Чтобы упростить задачу, рассмотрите запущенный поток main() создает поток, выполняющийся other():

LONG foo;

main()
{
  foo = TRUE;
  createthread(other());
  /* do other things */
  if(InterlockedExchange(&foo, 0))
  {
     cleanup()
  }
}

other()
{
  /* do other things */
  if(InterlockedExchange(&foo, 0))
  {
     cleanup()
  }
}

cleanup()
{
/* it's expected this is only called once */
}

Возможно ли в этом примере, что foo не будет отображаться как ИСТИНА ни для одного из вызовов InterlockedExchange? Если main занят другими делами, так что первый вызов InterlockedExchange выполняется из другого потока, означает ли это foo гарантируется, что он был написан основным потоком и виден другим потоком в это время?

Извините, если это непонятно, я не знаю, как это лучше сформулировать.


person newguy    schedule 20.11.2020    source источник
comment
См. В C / C ++ гарантированы изменчивые переменные иметь в конечном итоге согласованную семантику между потоками? для получения дополнительных указателей и обсуждения отчасти связанного с этим вопроса.   -  person dxiv    schedule 21.11.2020


Ответы (1)


Считывание / запись LONG в Windows без взаимосвязанных функций атомарно?

Да для обоих, при условии выравнивания по умолчанию. Это следует из процитированного оператора простые операции чтения и записи в правильно выровненные 32-разрядные переменные являются атомарными операциями, потому что LONG - это 32-разрядное целое число со знаком в Windows, независимо от разрядности ОС.

Возможно ли в этом примере, что foo не будет отображаться как ИСТИНА ни для одного из вызовов InterlockedExchange?

Нет, невозможно, если достигнуты оба вызова. Это потому, что внутри одного потока foo = TRUE; запись гарантированно будет видима для InterlockedExchange вызова, который следует после нее. Таким образом, вызов InterlockedExchange в main увидит либо значение TRUE, ранее установленное в main, либо сброс значения FALSE в потоке other. Следовательно, один из вызовов InterlockedExchange должен читать значение foo как TRUE.

Однако, если код /* do other things */ в main является бесконечным циклом while(1);, тогда останется только один InterlockedExchange в other, и этот вызов может увидеть foo как FALSE по той же причине, что и ...

Если main занят другими делами, так что первый вызов InterlockedExchange выполняется из другого потока, означает ли это, что foo гарантированно записан основным потоком и в это время виден другому потоку?

Не обязательно. Запись foo = TRUE; видна потоку main в момент создания вторичного потока, но не обязательно может быть видна потоку other при запуске или даже когда он доходит до вызова InterlockedExchange.

person dxiv    schedule 21.11.2020
comment
Разве создание потока other не вызовет некую очистку кеша или запись в память, чтобы все до этого момента было видно другим потокам? - person newguy; 23.11.2020
comment
@newguy Может и так, но такой гарантии прописанной в справочной документации я не нашел. - person dxiv; 23.11.2020
comment
В порядке. Я отметил ваш ответ как правильный. Спасибо за вашу помощь! - person newguy; 23.11.2020
comment
@newguy Рад / надеюсь, что это помогло. Что касается последней части, в частности, Синхронизация и многопроцессорность На странице «Проблемы» перечислены функции, связанные с критическими разделами, объектами синхронизации, ожиданием и заблокированным доступом, с использованием соответствующих барьеров для обеспечения упорядочения памяти, но CreateThread не входит в этот список. - person dxiv; 23.11.2020