多个线程访问同一资源时,为了保证数据的一致性,最简单的方式就是使用 mutex(互斥锁)。ios
引用 cppreference 的介绍:安全
The mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.
直接操做 mutex,即直接调用 mutex 的 lock / unlock
函数。函数
#include <iostream> #include <mutex> #include <thread> #include <vector> std::mutex g_mutex; int g_count = 0; void Counter() { g_mutex.lock(); int i = ++g_count; std::cout << "count: " << i << std::endl; // 前面代码若有异常,unlock 就调不到了。 g_mutex.unlock(); } int main() { const std::size_t SIZE = 4; // 建立一组线程。 std::vector<std::thread> v; v.reserve(SIZE); for (std::size_t i = 0; i < SIZE; ++i) { v.emplace_back(&Counter); } // 等待全部线程结束。 for (std::thread& t : v) { t.join(); } return 0; }
惋惜的是,STL 没有提供 boost::thread_group
这样表明一组线程的工具,经过 std::vector
当然也能达到目的,可是代码不够简洁。工具
使用 lock_guard
自动加锁、解锁。原理是 RAII,和智能指针相似。atom
#include <iostream> #include <mutex> #include <thread> #include <vector> std::mutex g_mutex; int g_count = 0; void Counter() { // lock_guard 在构造函数里加锁,在析构函数里解锁。 std::lock_guard<std::mutex> lock(g_mutex); int i = ++g_count; std::cout << "count: " << i << std::endl; } int main() { const std::size_t SIZE = 4; std::vector<std::thread> v; v.reserve(SIZE); for (std::size_t i = 0; i < SIZE; ++i) { v.emplace_back(&Counter); } for (std::thread& t : v) { t.join(); } return 0; }
使用 unique_lock
自动加锁、解锁。unique_lock
与 lock_guard
原理相同,可是提供了更多功能(好比能够结合条件变量使用)。
注意:mutex::scoped_lock
其实就是 unique_lock<mutex>
的 typedef
。线程
至于 unique_lock
和 lock_guard
详细比较,可移步 StackOverflow。指针
#include <iostream> #include <mutex> #include <thread> #include <vector> std::mutex g_mutex; int g_count = 0; void Counter() { std::unique_lock<std::mutex> lock(g_mutex); int i = ++g_count; std::cout << "count: " << i << std::endl; } int main() { const std::size_t SIZE = 4; std::vector<std::thread> v; v.reserve(SIZE); for (std::size_t i = 0; i < SIZE; ++i) { v.emplace_back(&Counter); } for (std::thread& t : v) { t.join(); } return 0; }
为输出流使用单独的 mutex。
这么作是由于 IO 流并非线程安全的!
若是不对 IO 进行同步,此例的输出极可能变成:code
count == count == 2count == 41 count == 3
由于在下面这条输出语句中:ip
std::cout << "count == " << i << std::endl;
输出 "count == " 和 i 这两个动做不是原子性的(atomic),可能被其余线程打断。资源
#include <iostream> #include <mutex> #include <thread> #include <vector> std::mutex g_mutex; std::mutex g_io_mutex; int g_count = 0; void Counter() { int i; { std::unique_lock<std::mutex> lock(g_mutex); i = ++g_count; } { std::unique_lock<std::mutex> lock(g_io_mutex); std::cout << "count: " << i << std::endl; } } int main() { const std::size_t SIZE = 4; std::vector<std::thread> v; v.reserve(SIZE); for (std::size_t i = 0; i < SIZE; ++i) { v.emplace_back(&Counter); } for (std::thread& t : v) { t.join(); } return 0; }