2015-03-05 6 views
3

Чтобы понять, как использовать Atomics в C++ 11, я попытался следующий фрагмент кода:нить :: присоединиться() блоки, когда он не должен

#include <iostream> 
#include <thread> 
#include <atomic> 

using namespace std; 

struct solution { 
    atomic<bool> alive_; 
    thread thread_; 

    solution() : thread_([this] { 
     alive_ = true; 
     while (alive_); 
    }) { } 
    ~solution() { 
     alive_ = false; 
     thread_.join(); 
    } 
}; 

int main() { 
    constexpr int N = 1; // or 2 
    for (int i = 0; i < N; ++i) { 
     solution s; 
    } 
    cout << "done" << endl; 
} 

Если N равно 1, то выход done , Однако, если я установил его равным 2, основной поток блокирует thread: join(). Почему вы думаете, что мы не видим done при N> 1?

Примечание: Если я использую следующий конструктор:

solution() : alive_(true), thread_([this] { 
     while (alive_); 
    }) { } 

печатает done при любом значении N.

ответ

9

Если вы не инициализирует alive_ и установить только один раз начинается нить, то следующее чередование выполнения можно:

MAIN: s::solution() 
MAIN: s.thread_(/*your args*/) 
MAIN: schedule(s.thread_) to run 
thread: waiting to start 
MAIN: s::~solution() 
MAIN: s.alive_ = false 
thread: alive_ = true 
MAIN: s.thread_.join() 
thread: while(alive_) {} 
4

atomic<bool>, по умолчанию, инициализируются ложна на Visual Studio (это s начальное значение не определено стандартом). Итак, следующая последовательность событий может произойти:

  1. Объект Решение создается, alive_ инициализируется false и thread_ создается (но не запускать).

  2. Объект раствора разрушен, работает деструктор и устанавливает alive_ ложь, а затем ждут thread_ до конца (нить ничего не сделали)

  3. thread_ работает, устанавливают alive_ к истинному, а затем зацикливается (потому что основной поток ждет его завершения).

+1

@ Ангел написал ранее, поэтому я пометил его ответ как правильный. –

+3

'atomic ' по умолчанию не инициализируется 'false': [atomics.types.generic]/5 требует, чтобы атомы имели тривиальные конструкторы по умолчанию. Обратите внимание, что реализация стандартной библиотеки Visual C++ * делает * значение-инициализировать атомику, которая не соответствует требованиям. – Casey

+0

@ Casey интересно, вы правы (29.5/5, что я бы оценил, если бы вы упомянули). Во всяком случае, это только более сильный аргумент для явной инициализации флага. –

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