递归锁 recursive_mutex

如果一个mutex被许多模块和类共享,就使用boost::recursive_mutex,如果只被一个模块和类使用,而且不需要re-entrant特性, 就使用boost::mutex

特点:

  1. 递归锁是互斥锁的一种,同一线程对其多次加锁不会产生死锁。
  2. 递归锁会使用引用计数机制,以便可以从同一线程多次加锁、解锁,当加锁、解锁次数相等时,锁才可以被其他线程获取。
  3. 能用普通互斥锁就不要用递归锁,会增大开销
  4. 无法定义lock递归锁的次数,当然也不是无限的,次数太多会有报错
  5. 递归锁也可以在循环中使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <ros/ros.h>
#include <ros/console.h>
#include <boost/thread.hpp>
#include <iostream>
using namespace std;

boost::mutex mtx;

void bar()
{
// ! dead-locked here
boost::mutex::scoped_lock lLock(mtx);
std::cout << "bar" << std::endl;
}

void foo()
{
boost::mutex::scoped_lock lLock(mtx);
std::cout << "foo" << std::endl;
}

int main(int argc, char **argv)
{
ros::init(argc, argv, "test_curve");
ros::NodeHandle n;

foo();
bar();
return 0;
}

这种情况下,线程正常运行,不会死锁。

但是这种情况下,线程就死锁了,只能运行foo,因为mutex不可重入,foo这个线程没有运行完

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <ros/ros.h>
#include <ros/console.h>
#include <boost/thread.hpp>
#include <iostream>
using namespace std;

boost::mutex mtx;

void bar()
{
boost::mutex::scoped_lock lLock(mtx); // dead-locked here
std::cout << "bar" << std::endl;
}

void foo()
{
boost::mutex::scoped_lock lLock(mtx);
std::cout << "foo" << std::endl;
bar();
}

int main(int argc, char **argv)
{
ros::init(argc, argv, "test_curve");
ros::NodeHandle n;

foo();
return 0;
}

如果把mutex换成recursive_mutex,又能正常运行了。

recursive_mutex类可多次进入锁,这样在递归时可以避免一次死锁的几率,这是原本BOOST中所体现的一种思想。递归锁可多次锁,同样的需要多次解锁,那么问题就来了,如果真正或可能造成这次死锁的位置在某个已经进入死锁的地方,那么死锁的位置可能并不是你需要的位置,简单的说,如果A锁了3次,B锁一次,C锁一次,这样就锁出现死锁,排错之困难可想而知。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <ros/ros.h>
#include <boost/thread.hpp>
#include "boost/thread/mutex.hpp"
using namespace std;

boost::recursive_mutex mtx;
int sum = 10;

void thread_1(int n)
{
mtx.lock();
mtx.lock();
mtx.lock();
sum = sum * n;
cout<<"thread 1, sum: "<< sum <<endl;
mtx.unlock();
// mtx.unlock();
// mtx.unlock();
}

void thread_2(int n)
{
mtx.lock();
sum = sum * 7 * n;
cout<<"thread 2, sum: "<< sum <<endl;
mtx.unlock();
}

int main()
{
unsigned int n = 2;
boost::thread th_1 = boost::thread(boost::bind(&thread_1, n) );
boost::thread th_2 = boost::thread(boost::bind(&thread_2, n) );

th_1.join();
th_2.join();
return 0;
}

thread_1里如果lock3次,unlock1次,运行时会阻塞在thread_1。只有3次unlock才会正常运行两个线程。