以下代码来自modernescpp。我了解当主线程中的互斥锁中的lock_guard导致死锁时。但是由于创建的线程应该在初始化后立即开始运行。第15行之后,第11行上的lock_guard函数是否有可能已经抓住了coutMutex,因此代码运行没有任何问题?如果可能,在什么情况下创建线程 首先运行?
#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();
}
}
答案 0 :(得分:2)
因此,答案将被发布为答案,而不是评论:
尤其是,主线程可以创建从属线程,然后都挂起。从那时起,由OS调度程序决定下一步运行哪个。由于主线程是最近才运行的,因此很有可能会选择下一个线程来运行(假设在没有优先级差异的情况下,它尝试遵循模糊调度(如循环调度)之类的方法,或者给它一个优先安排哪个线程。
有多种方法可以解决死锁的可能性。一种明显的可能性是将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
。这样,您只需要锁定足够长的时间就可以向队列添加缓冲区或从队列中删除缓冲区。