2014-10-09 3 views
9

Я изучаю мьютексы на C++ и имею проблему со следующим кодом (взятым из N. Josuttis «Стандартная библиотека C++»).Программа на C++ неожиданно блокирует/бросает

Я не понимаю, почему он блокирует/бросков , если я не добавитьthis_thread::sleep_for в главном потоке (тогда он не блокирует и все три вызова выполняется).

Компилятор cl.exe, используемый в командной строке.

#include <future> 
#include <mutex> 
#include <iostream> 
#include <string> 
#include <thread> 
#include <chrono> 

std::mutex printMutex; 

void print(const std::string& s) 
{ 
    std::lock_guard<std::mutex> lg(printMutex); 

    for (char c : s) 
    { 
     std::cout.put(c); 
    } 
    std::cout << std::endl; 
} 

int main() 
{ 
    auto f1 = std::async(std::launch::async, print, "Hello from thread 1"); 
    auto f2 = std::async(std::launch::async, print, "Hello from thread 2"); 

    // std::this_thread::sleep_for(std::chrono::seconds(1)); 

    print(std::string("Hello from main"));  
} 
+3

Вы не ожидали окончания нитей. Я думаю, что это проблема с библиотекой MSVC. – Niall

ответ

11

Я думаю, что то, что вы видите, является проблемой с выполнением MSVC async (в сочетании с future). Я считаю, что это not conformant. Я могу воспроизвести его с помощью VS2013, но не смог воспроизвести проблему с gcc.

Аварийный сигнал возникает из-за того, что основной поток выходит (и начинает очищаться) до завершения двух других потоков.

Следовательно, простая задержка (sleep_for) или .get() или .wait() на двух фьючерсах должна исправить это для вас. Таким образом, может быть изменен main;

int main() 
{ 
    auto f1 = std::async(std::launch::async, print, "Hello from thread 1"); 
    auto f2 = std::async(std::launch::async, print, "Hello from thread 2"); 

    print(std::string("Hello from main"));  

    f1.get(); 
    f2.get(); 
} 

Одобрить явное ожидание или переиграть приуроченный «сон».

Заметки о соответствии

Было предложение от Herb Sutter изменить ожидание или блок на разделяемом состоянии future вернулись из async. Это может быть причиной поведения в MSVC, это можно рассматривать как воплощение этого предложения. Я не уверен, каким окончательным результатом было предложение или его интеграция (или его часть) в C++ 14. По крайней мере, w.r.t. блокировка future, возвращенная с async, похоже, что поведение MSVC не входило в спецификацию.

Интересно отметить, что формулировка в §30.6.8/5 изменено;

От C++ 11

вызова к функции ожидания на асинхронном объекте возврата, который разделяет общее состояние, созданного этим async вызова не будет блокировать до соответствующей нити завершен, как если бы присоединился

для C++ 14

вызов к функции ожидания на асинхронном объекта возврата, который разделяет т он разделил государство, созданное этим async вызов должен блокироваться, пока связанный поток не завершен, как если бы присоединился, или еще раз из

Я не знаю, как будет указан «тайм-аут», Я бы предположил, что это реализация.

+0

Итак, каково ожидаемое поведение? Нитки, работающие без ссылки на них, возможно, после прекращения основной нити, должны продолжать работать, подобно индейке с отключенной головкой – Mikhail

+0

@Mikhail. Мне нравится аналог индейки, LOL. Я думаю, именно поэтому предложение, вероятно, было отвергнуто (по крайней мере, часть, где потоки отключены от любого состояния ожидания). Я думаю, что это лучшая идея для «будущего», возвращаемого из «async» для блокировки. Я также думаю, что иногда возникает путаница вокруг источника «будущего» и будет ли он блокироваться или нет - возможно, «async_future», возможно, была лучшей идеей, но я не знаю. Я считаю, что «асинк» был поздним дополнением, поэтому они не могли бы устранить все более тонкие проблемы. – Niall

1

std::async возвращает future. Его destructor блоков, если get или wait не были вызваны:

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

См. std::futures from std::async aren't special! для детальной обработки предмета.

+2

Так как это объясняет крах? –

+2

Как это объяснить, что он работает, если он спит на секунду? –

1

Добавьте эти 2 строки в конце main:

f1.wait(); 
f2.wait(); 

Это удостоверится нити закончить до main существует.

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