2016-10-14 2 views
2

Рассмотрим следующие два потока исполнения:атомное упорядочение памяти и прерывания цикла сообщений

Тема A:

// Initialize stuff... 
std::atomic<bool> interrupted = false; 

// Launch thread B 
// ... Do some useful stuff 

// Interrupt B 
interrupted = true; 
InterruptMessageLoop(B); 

Thread B

RunMessageLoop(); // Can exit by itself or due to InterruptMessageLoop 
if (interrupted) { 
    // Do something special 
} 

вопрос, что у меня есть - может Я уверен, что если нить A действительно вызовет InterruptMessageLoop, поток B увидит атом interrupted в состоянии true? (Я имею в виду это «желаемое поведение» ниже)

Проблемы, которую я вижу в том, что, если я правильно понимаю, упорядоченность памяти std::memory_order_seq_cst, который используется в operator= вариабельных гарантиях атомных, что не нормально пишет будет переупорядочено после атомной операции и нет нормального читает будет переупорядочено до атомной операции. Но может случиться так, что поток A переупорядочивает InterruptMessageLoop(B) до атома, тогда поток B прерывает цикл сообщения и считывает неверное значение (относительно логического значения) interrupted, и только тогда поток A записывает в interrupted. Это верно? И если да, есть ли способ убедиться, что я получаю поведение, которое я хочу, не прибегая к мьютексу (т. Е. Оберните InterruptMessageLoop и булевскую модификацию в мьютекс и заблокируйте один и тот же мьютекс при чтении)?

Обратите внимание, что я не контролирую реализацию RunMessageLoop.

Редактировать Обратите внимание, что ситуация, когда я выполняю команду, чтобы прервать цикл и цикл существует нормально (вроде игнорирования моей команды) - это нормально в моем случае, когда поток B считает, что прерывание вызывается цикл обработки сообщений выйти.

ответ

0

Чтобы точно отличить, была ли RunMessageLoop закончена нормально или из-за InterruptMessageLoop, вам придется полагаться на какой-то статус, о котором говорит RunMessageLoop.

Хакерный способ, который вы пытаетесь сделать, не будет работать. Скажем, вам удалось гарантировать, что компилятор ничего не записывает. Вы по-прежнему имеют следующий перемежения:

  • Т1: (А) = прервала истинно
  • Т2: (В) RunMessageLoop() закончил нормально.
  • T3: (A) InterruptMessageLoop()
  • T4: (B) если (прервано) возвращает true, но B не прерывается!
+0

Спасибо. Однако, как я сказал в записке, я не контролирую реализацию «RunMessageLoop», поэтому я не могу отличить две ситуации на основе того, что он мне говорит. Тем не менее, ситуация, о которой вы описали, совершенно прекрасна - я беспокоюсь только в том случае, когда я выдаю команду на прерывание цикла, а потом я не могу сказать, что я сделал из потока B. – Rostislav

+1

Я не мог сказать из ваше первоначальное описание, что вы допускаете определенные ошибки, но не некоторые другие ошибки, при принятии решения о том, действительно ли RunMessageLoop прерван потоком A. Но в этом случае взгляните на барьер памяти, например http://stackoverflow.com/questions/8841738/c-memory-barriers-for-atomics. Надеюсь, поможет. –

+0

Да, я понимаю, это было совершенно неясно - спасибо за это! Я посмотрю на барьеры памяти. – Rostislav