網上很容易找到一個用boost::shared_mutex來作為讀寫鎖的例子:
- typedef boost::shared_mutex rwmutex;
- typedef boost::shared_lock<rwmutex> readLock;
- typedef boost::unique_lock<rwmutex> writeLock;
typedef boost::shared_mutex rwmutex;
typedef boost::shared_lock<rwmutex> readLock;
typedef boost::unique_lock<rwmutex> writeLock;
一直沒有懷疑過這個做法,直到最近項目中出現一個死鎖問題,查了很久才發現是上面這種寫法造成的。
寫測試代碼還原死鎖的情景如下:
- #include <boost/thread/shared_mutex.hpp>
- #include <boost/thread/shared_lock_guard.hpp>
- #include <boost/thread.hpp>
- #include <iostream>
- #include <Windows.h>
- using namespace std;
- typedef boost::shared_mutex rwmutex;
- typedef boost::shared_lock<rwmutex> readLock;
- typedef boost::unique_lock<rwmutex> writeLock;
-
- rwmutex m_mutex;
- void func1()
- {
- writeLock lock1(m_mutex);
- cout << "fffffffffffffff" << endl;
- }
-
- int main()
- {
- {
- boost::thread tt(func1);
- readLock lock(m_mutex);
- {
- Sleep(3000);
- readLock lock(m_mutex);
- cout << "rrrrrrrrrrrrrrrrrr" << endl;
- }
- }
- }
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/shared_lock_guard.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <Windows.h>
using namespace std;
typedef boost::shared_mutex rwmutex;
typedef boost::shared_lock<rwmutex> readLock;
typedef boost::unique_lock<rwmutex> writeLock;
rwmutex m_mutex;
void func1()
{
writeLock lock1(m_mutex);
cout << "fffffffffffffff" << endl;
}
int main()
{
{
boost::thread tt(func1);
readLock lock(m_mutex); // 加讀鎖
{
Sleep(3000); // 故意睡眠3秒將線程切換出去
readLock lock(m_mutex); // 醒來后再次加讀鎖
cout << "rrrrrrrrrrrrrrrrrr" << endl;
}
}
}
情形描述如下:
1:主線程先給m_mutex加讀鎖。
2:主線程故意睡眠3秒將執行權限切換出去。
3:func1線程獲得執行機會,嘗試加寫鎖被掛起。因為主線程已經有一個讀鎖占用,寫鎖必須等待這個讀鎖釋放才能進入。
4:主線程睡眠3秒醒來,后續代碼想獲取一個讀鎖。由于這個時候已經有一個寫鎖在等待進入,那么這個讀鎖排隊在寫鎖后面,同樣被掛起。
5:主線程和func1線程都被掛起了,發生死鎖。
上面的測試代碼,如果中間沒有sleep(3000),出現死鎖的概率很低,但總歸是存在死鎖的可能。
總結:
以前一直認為readLock鎖和遞歸鎖一樣,在同一個線程多次進入沒有關系才會造成上面的死鎖出現。所以,boost::shared_lock使用要小心,千萬不要同一個線程多次進入。