C++ 并发编程(二):Mutex(互斥锁)

多个线程访问同一资源时,为了保证数据的一致性,最简单的方式就是使用 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 1

直接操做 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 当然也能达到目的,可是代码不够简洁。工具

Mutex 2

使用 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;
}

Mutex 3

使用 unique_lock 自动加锁、解锁。
unique_locklock_guard 原理相同,可是提供了更多功能(好比能够结合条件变量使用)。
注意:mutex::scoped_lock 其实就是 unique_lock<mutex>typedef线程

至于 unique_locklock_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 4

为输出流使用单独的 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;
}
相关文章
相关标签/搜索