互斥器:使用得最多的同步原语
互斥锁的详细介绍在这一篇博文中:
概念补充:RAII——资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。只要对象能正确地析构,就不会出现资源泄漏问题。
互斥器保护了临界区,任何一个时刻最多只能有一个线程在此mutex划出的临界区内活动。单独使用mutex时,主要为了保护共享数据。原则:
-用RAII手法封装mutex的创建,销毁,加锁,解锁四个操作。
-只用非递归的mutex(即不可重入的mutex)
-不手工调用lock()和unlock()函数,一切交给Guard对象的构造和析构函数负责。Guard对象的生命期正好等于临界区。
-每次构造Guard对象的时候,思考已持有的锁,防止因加锁顺序不同而导致死锁。
1.只使用非递归的mutex
mutex分为递归(recursive)和非递归(non-recursive)两种。另一种叫法是:可重入与非可重入。
在同一线程里多次对non-recursive mutex加锁会立刻导致死锁,而recursive mutex不用考虑线程自己把自己锁死
但recursive mutex可能会隐藏代码里的一些问题,例如:
拿到一个锁就开始修改对象,但是没想到外层代码也拿到了锁,正在修改同一个对象。
- MutexLock mutex;
- std::vector<Foo> foos;
- void post(const Foo& f)
- {
- MutexLockGuard lock(mutex);
- foos.push_back(f);
- }
- void traverse()
- {
- MutexLockGuard lock(mutex);
- for (std::vector<Foo>::const_iterator it = foos.begin(); it != foos.end(); ++it)
- {
- it->doit();
- }
- }