2017-02-11 3 views
1

У меня есть код на работе, который запускает несколько потоков, которые выполняют некоторые операции, и если какой-либо из них не работает, они устанавливают общую переменную в false.Есть ли неявный барьер памяти с синхронизированным отношением на thread :: join?

Затем основной поток объединяет все рабочие потоки. Моделирование это выглядит примерно так (я закомментирована возможным исправление, которые я не знаю, если это необходимо):

#include <thread> 
#include <atomic> 
#include <vector> 
#include <iostream> 
#include <cassert> 

using namespace std; 

//atomic_bool success = true; 
bool success = true; 

int main() 
{ 
    vector<thread> v; 
    for (int i = 0; i < 10; ++i) 
    { 
     v.emplace_back([=] 
     { 
      if (i == 5 || i == 6) 
      { 
       //success.store(false, memory_order_release); 
       success = false; 
      } 
     }); 
    } 
    for (auto& t : v) 
     t.join(); 

    //assert(success.load(memory_order_acquire) == false); 
    assert(success == false); 

    cout << "Finished" << endl; 
    cin.get(); 
    return 0; 
} 

Есть ли вероятность того, что основной поток будет читать переменный успех, как истинного даже если один из рабочих установил его на false?

Я обнаружил, что нити :: присоединиться() барьер полной памяти (source) но что подразумевает синхронизируется-с связи со следующим читают успеха переменных от основного потока, так что мы 'гарантированно получить самую новую ценность?

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

Есть ли вероятность того, что читает успеха переменные будет оптимизированы прочь (поскольку это не летучее), и мы получим старое значение независимо от suppossed существовать барьер неявной памяти на нити :: присоединиться?

Код допускается работать с несколькими архитектурами (не помню всех из них, у меня нет makefile передо мной), но есть atleast x86, amd64, itanium, arm7.

Спасибо за любую помощь.

Редактировать: Я изменил пример, потому что в реальной ситуации более чем один поток может попытаться записать в успех переменной.

+1

Не ясно ли об этом источник? «Поскольку создание и структура потока определяется как операция синхронизации, объединение потока обязательно происходит после завершения этого потока. Таким образом, вы увидите все, что обязательно произошло до прекращения потока». –

+0

Я не уверен, так как вы можете увидеть здесь http: //en.cppreference.com/w/cpp/atomic/atomic_thread_fence ссылается только на синхронизацию между заборами и атомными объектами, ничего не происходит о синхронизации между ограждениями и обычными объектами. Я думаю, что объединение использует такой забор внутри, но я могу ошибаться. – Mikaka

+1

[Да] (https://timsong-cpp.github.io/cppwp/thread.thread.member#4). В противном случае «join» будет бесполезным. –

ответ

1

Приведенный выше код представляет собой гонку данных, и использование join не может изменить этот факт. Если бы только один поток написал переменную, все было бы хорошо. Но у вас есть два потока, пишущих на него, с no синхронизация между ними. Это гонка данных.

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

Если вы использовали atomic_bool, то это не было бы UB; это будет гарантировано ложным. Но поскольку есть гонка данных, вы получаете чистый UB. Это могут быть истинные, ложные или носовые демоны.

+0

Хорошо, я получаю неопределенную часть поведения. Но предполагая, что мы находимся на платформе, где write to bool является атомарным, и мой поток (тот, который объединяет всех работников) является единственным, кто читает флаг * success *, будет * join * быть достаточным, чтобы гарантировать правильный порядок, и я буду всегда видеть * false *, если какой-либо рабочий задал его или я могу получить * true *? – Mikaka

+0

@ Mikaka: «* Но если мы находимся на платформе, где write to bool is atom *» Нет. Вы спросили о C++. Я говорю вам, что C++ гарантирует. Как «произвольная платформа, на которую я надеюсь, делает что-то разумное», ведет себя по-разному между вами и вашей платформой выбора. Если вы хотите, чтобы это было * гарантировано * для работы, вы используете фактический 'атомный '. Если это платформа, которая ведет себя так, как вы думаете, то «атомный » будет просто тонкой оболочкой вокруг «bool». И если это не так, то все равно будет правильно. –

Смежные вопросы