多个线程访问同一资源时,为了保证数据的一致性,最简单的方式就是使用 mutex(互斥锁)。
引用 cppreference 的介绍:
The mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.
方法1:直接操作 mutex,即直接调用 mutex 的 lock / unlock
函数
此例顺带使用了 boost::thread_group
来创建一组线程。
#include <iostream> #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> boost::mutex mutex; int count = 0; void Counter() { mutex.lock(); int i = ++count; std::cout << "count == " << i << std::endl; // 前面代码如有异常,unlock 就调不到了。 mutex.unlock(); } int main() { // 创建一组线程。 boost::thread_group threads; for (int i = 0; i < 4; ++i) { threads.create_thread(&Counter); } // 等待所有线程结束。 threads.join_all(); return 0; }
方法2:使用 lock_guard
自动加锁、解锁。原理是 RAII,和智能指针类似
#include <iostream> #include <boost/thread/lock_guard.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> boost::mutex mutex; int count = 0; void Counter() { // lock_guard 在构造函数里加锁,在析构函数里解锁。 boost::lock_guard<boost::mutex> lock(mutex); int i = ++count; std::cout << "count == " << i << std::endl; } int main() { boost::thread_group threads; for (int i = 0; i < 4; ++i) { threads.create_thread(&Counter); } threads.join_all(); return 0; }
方法3:使用 unique_lock
自动加锁、解锁unique_lock
与 lock_guard
原理相同,但是提供了更多功能(比如可以结合条件变量使用)。
注意:mutex::scoped_lock
其实就是 unique_lock<mutex>
的 typedef
。
#include <iostream> #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> boost::mutex mutex; int count = 0; void Counter() { boost::unique_lock<boost::mutex> lock(mutex); int i = ++count; std::cout << "count == " << i << std::endl; } int main() { boost::thread_group threads; for (int i = 0; i < 4; ++i) { threads.create_thread(&Counter); } threads.join_all(); return 0; }
方法4:为输出流使用单独的 mutex
这么做是因为 IO 流并不是线程安全的!
如果不对 IO 进行同步,此例的输出很可能变成:
count == count == 2count == 41 count == 3
因为在下面这条输出语句中:
std::cout << "count == " << i << std::endl;
输出 "count == " 和 i 这两个动作不是原子性的(atomic),可能被其他线程打断。
#include <iostream> #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> #include <boost/thread/lock_guard.hpp> boost::mutex mutex; boost::mutex io_mutex; int count = 0; void Counter() { int i; { boost::unique_lock<boost::mutex> lock(mutex); i = ++count; } { boost::unique_lock<boost::mutex> lock(io_mutex); std::cout << "count == " << i << std::endl; } } int main() { boost::thread_group threads; for (int i = 0; i < 4; ++i) { threads.create_thread(&Counter); } threads.join_all(); return 0; }