关于读写锁可查看:多线程之读写锁(unique_lock与shared_lock)
多个线程访问同一资源时,为了保证数据的一致性,最简单的方式就是使用 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;
}
关于join_all()函数可查看:多线程之std::thread join()函数
方法4:为输出流使用单独的 mutex
这么做是因为 IO 流并不是线程安全的!
如果不对 IO 进行同步,此例的输出很可能变成:
count == count == 2count == 41
count == 3
因为在下面这条输出语句中:
std::cout << "count == " << i << std::endl;
输出 "count == " 和 i 这两个动作不是原子性的(atomic),可能被其他线程打断。
注:原子性,原子是世界上的最小单位,具有不可分割性。比如 a=0;这个操作是不可分割的,那么我们说这个操作是原子操作。再比如:a++;这个操作实际是a = a + 1;是可分割的(先a+1,然后a=a+1),所以他不是一个原子操作。 非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。
#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;
}