Просто ответ будет опубликован в виде ответа, а не комментария:
- Нет, этот код не гарантирован до тупика.
- Даэтот код вполне вероятен для взаимоблокировки.
В частности, основной поток может создать подчиненный поток, а затем оба будут приостановлены.Начиная с этого момента, планировщик ОС решает, что делать дальше.Так как основной поток был запущен совсем недавно, есть большая вероятность, что он выберет подчиненный поток для запуска в следующем (при условии, что он пытается следовать чему-то неопределенному, например, циклическому планированию при отсутствии разницы в приоритете, или что-то подобное, давая емупредпочтение тому, какой поток запланировать).
Существуют различные способы исправить возможность взаимоблокировки.Одна очевидная возможность состоит в том, чтобы переместить join
за пределы области видимости, в которой основной поток содержит мьютекс:
#include <iostream>
#include <mutex>
#include <thread>
std::mutex coutMutex;
int main(){
std::thread t([]{
std::cout << "Still waiting ..." << std::endl;
std::lock_guard<std::mutex> lockGuard(coutMutex); // Line 11
std::cout << std::this_thread::get_id() << std::endl;
}
);
// Line 15
{
std::lock_guard<std::mutex> lockGuard(coutMutex);
std::cout << std::this_thread::get_id() << std::endl;
}
t.join();
}
Я бы также избежал блокировки мьютекса на время использования std::cout
,cout
обычно достаточно медленный, что может привести к конфликту из-за блокировки.Обычно лучше (только для одного примера) отформатировать данные в буфере, поместить буфер в очередь и иметь один поток, который считывает элементы из очереди и отправляет их в cout
.Таким образом, вам нужно будет блокировать только достаточно долго, чтобы добавить / удалить буфер в / из очереди.