前言
在C++11新标准发行之前,C++并发编程往往依靠第三方的函数库,如:Linux下的pthread。多线程环境下,线程安全问题往往是程序员关注的重点。然而,古人云:线程安全问题单单依靠库函数是没办法完全解决的。Threads Cannot be Implemented as a Library 这篇文章比较详细的叙述了其中的原因,有兴趣的童鞋可以去看看。C++ 11开始引入了多线程的标准,这是多么欢欣鼓舞的事情,今天来谈谈多线程中很重要的一个事情,就是锁。
正文
新标准下的关于锁的内容几乎都在头文件mutex
中。常用的锁,包括:mutex
、recursive_lock
都为我们提供如下函数:
void lock() //阻塞版本的上锁,失败则阻塞。属于空闲等待锁
bool try_lock() //非阻塞版本的上锁,成功返回true,失败返回false。属于忙等待锁
void unlock() //解锁
从字面意思就可以看出,mutex是普通的非递归锁,而recursive_mutex为递归锁。他们的区别在于,同一个线程对多次上锁后的行为。对于前者,这种操作是不被允许的,而对于后者,这种行为是被允许的。来看如下示例1-4:
void main()
{
// 示例1:同一个mutex对象连续调拥两次lock
mutex m1;
m1.lock();
m1.lock();
m1.unlock();
}
执行的结果是抛出异常并执行abort()。
void main()
{
// 示例2:对同一个mutex对象调用两次try_lock
mutex m1;
cout << m1.try_lock() << endl;
cout << m1.try_lock() << endl;
m1.unlock();
}
结果:
1
0
程序能够正常结束,说明try_lock()
并没有阻塞线程而进行等待,也不会抛出异常。前面提到try_lock是忙等待锁,因为它无法阻塞自己,想要获取锁,必须不停的尝试上锁。
void main()
{
// 示例3:对同一个recursive_mutex调用两次lock
recursive_mutex rm;
rm.lock();
rm.lock();
rm.unlock();
rm.unlock();
}
结果是程序正常的执行结束,没有出现死锁的情况。然而,值得注意的是:程序中需要两次释放锁,否则抛出异常。
void main()
{
//示例4:对同一个recursive_mutex对象调用两次try_lock
recursive_mutex rm;
cout << rm.try_lock() << endl;
cout << rm.try_lock() << endl;
rm.unlock();
rm.unlock();
}
程序执行的结果是: