死锁与调度有关

时间:2014-12-29 23:10:13

标签: c++ multithreading c++11 concurrency

Oracle docs for multithreading上他们有一段关于在尝试要求锁定时死锁的段落:

  

因为没有保证获得锁定的顺序,a   线程程序中的问题是特定的线程永远不会   获得锁定,即使它似乎应该。

     

当持有锁的线程释放它时,通常会发生这种情况,   让少量时间过去,然后重新获取它。因为   锁已被释放,似乎另一个线程应该获得   锁。但是,因为没有什么阻止持有锁的线程,所以   从它释放锁定到它之间继续运行   重新获取锁,因此没有其他线程运行。

为了确保我理解这一点,我试着在代码中写出来(让我知道这是否是正确的解释):

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

std::mutex m;

void f()
{
    std::unique_lock<std::mutex> lock(m); // acquire the lock
    std::cout << std::this_thread::get_id() << " now has the mutex\n";

    lock.unlock(); // release the lock
    std::this_thread::sleep_for(std::chrono::seconds(2)); // sleep for a while

    lock.lock(); // reacquire the lock
    std::cout << std::this_thread::get_id() << " has the mutex after sleep\n";
}

int main()
{
    std::thread(f).join(); // thread A
    std::thread(f).join(); // thread B
}

那么上面的引言是说释放锁并且线程正在休眠的时间(如上面的代码)不足以保证线程等待锁获取它?这与死锁有什么关系?

1 个答案:

答案 0 :(得分:2)

该文件正在解决一种特定的公平问题,并将其纳入关于僵局的讨论中。该文档正确地定义了死锁,意味着“永久阻塞一组线程”。然后描述了一种不太明显的实现永久阻塞条件的方法。

在所描述的场景中,假设两个线程同时尝试获取相同的锁。只有一个会赢,所以称之为 W ,另一个输了,所以称之为 L 。失败者进入睡眠状态等待轮到锁定。

引用的文字说 L 可能永远不会有机会获得锁定,即使它是由 W 发布的。

这可能发生的原因是锁不会对哪个线程获得它的公平性施加影响。锁定非常乐意让 W 永久地获取和释放它。如果 W 以释放锁定后不需要上下文切换的方式实现,那么它可能最终会在 {{1}之前再次获取锁定有机会醒来看看锁是否可用。

因此,在下面的代码中,如果L赢得与W_thread的初始竞争,L_thread实际上已经陷入僵局,即使理论上它可以获得{{{}的迭代之间的锁定1}}。

L_thread

该文档建议使用W_thread强制将上下文切换到另一个线程。此API特定于Solaris / SunOS。它的POSIX版本称为void W_thread () { for (;;) { std::unique_lock<std::mutex> lock(m); //... } } void L_thread () { std::unique_lock<std::mutex> lock(m); //... } ,尽管某些UNIX版本(包括Linux)提供了一个名为thr_yield()的包装器。

在C ++ 11中,这是通过std::this_thread::yield()完成的。