最近打算写一个curl的C++11封装,使用Thread的时候出现了一个BUG,某一个线程始终持有一个锁,反复加锁解锁的过程。而另外一个线程卡死在lock上。大致代码如下:
std::mutex mtx;
//Thread 1
mtx.lock();
//...do something
mtx.unlock();
//Thread 2
do {
mtx.lock();
//...do something
mtx.unlock();
}while(true);
Thread 2在一个死循环内持有并加解锁。另外一个是普通的流程函数。
代码没有抛出异常导致死锁,起初以为是自己mutex不熟,用法有误,但是反复查证,用法应该没问题。并且奇妙的是如果在加锁前和解锁后打印日志就会正常。
难道是死循环导致的吗?
于是在Thread 2的unlock之后加了一句usleep:
mtx.unlock();
usleep(0);
在零X年的时候看过一篇帖子,说sleep(0)可以让线程放弃当前获得的cpu时间片。理论上这样就可以产生一个中断,让其他线程得到执行。
结果并没有变化。
难道那篇帖子说的不对么。又改了下:
mtx.unlock();
usleep(1);
结果正常了,2个线程都正确的加锁解锁。
事后总结,猜测就是因为Thread 2在解锁之后,再次加锁之前没有能够产生中断的函数,于是很快地又再次获得了锁,导致其他线程总是无法获得锁。这个问题和自旋锁在单核机器上无法正常工作是一个原理。