2015-03-02 2 views
2

У меня есть класс RAII, который решает проблему внутренней резьбы:Брошенный объект не может быть поймана в многопоточном растворе

#include <iostream> 
#include <thread> 
using namespace std; 

struct solution_using_thread { 
    solution_using_thread() 
    : alive_(true), thread_() { 
     thread_ = thread([this]() { 
      while(alive_); 
     }); 
    } 
    ~solution_using_thread() { 
     alive_ = false; 
     thread_.join(); 
    } 
private: 
    bool alive_; 
    thread thread_; 
}; 

int main() { 
    cout << 0 << endl; 
    try { 
     solution_using_thread solution; 
     throw 1; 
    } catch (int i) { 
     cout << i << endl; 
    } 
    cout << 2 << endl; 
} 

После создания экземпляра этого, главное случается бросить исключение. Проблема заключается в том, в некоторых исполнениях, выход:

0 

, когда оно всегда должно быть:

0 
1 
2 

В coliru, это всегда только 0.

Что мне здесь не хватает?

PS: Извините, за неоднозначное название. Пожалуйста, не стесняйтесь предлагать лучший вариант для этого вопроса.

ответ

1

Вы предполагаете, что поток (в конце концов) увидит обновленное значение alive_. Но это не гарантировано. Объекты без синхронизации: не гарантированно становится видимым для других потоков в любое конечное время. Возможно, значение alive_ кэшировано где-то и никогда не обновляется.

Вам нужна некоторая синхронизация, чтобы заставить его работать — либо использовать мьютекс, либо другой примитив синхронизации, либо сделать alive_ атомарным. Вот working example последнего:

#include <atomic> 

struct solution_using_thread { 
    solution_using_thread() 
    : alive_(true), thread_() { 
     thread_ = thread([this]() { 
      while(alive_); 
     }); 
    } 
    ~solution_using_thread() { 
     alive_ = false; 
     thread_.join(); 
    } 
private: 
    atomic<bool> alive_; 
    thread thread_; 
}; 

Без синхронизации, программа Неопределенное поведение, потому что два потока ввода гонки данных по alive_.

+0

Прежде чем принять ваш ответ, можете ли вы объяснить, почему раскрутка стека не блокируется в '' thread_.join() '' (в исходном коде)? –

+0

@bmm Добавил, что без синхронизации, это UB, так что все может случиться (в том числе и не блокировать). – Angew