c++11并发编程api

Forums: 

本帖罗列 c++ 11 中关于并发多线程编程的 api (application programming interface),实际上就是一些类和函数等。

线程创建

  • std::thread th{f}; f 是一个普通的函数,或是一个函数对象(functor),或是一个匿名函数;构造 th 对象后一个并发的线程流便开始执行,不需要显示地启动它;
  • thread th{f, a, b, c}; 向线程中传递参数,a、b、c 值传递给 th (线程对象),继而传递给函数 f;a、b、c 的类型和 f 参数的类型要匹配,或是一致;
  • thread th{f, a, std::ref(b), std::cref(c)}; 参数 a 值传递,参数 b 引用传递,参数 c 常引用传递;
  • thread th; th 是个线程对象,但是么有线程流(这都可以? O__O"…);
  • thread th{std::move(other)}; other 是个线程对象,让 th 代替 other 去执行线程流;std::move 是一个函数,将参数转换成一个右值;
  • std::thread::id tid = th.get_id(); 返回线程 id;可以 == != >= 进行比较和使用 cout 输出;
  • th.join(); 阻塞当前线程直到 th 执行完毕;如果 th.joinable() == false,则抛出 std::system_error;
  • bool b = th.joinable(); 查看 th 是不是活跃的线程,默认构造的 thread 不可以 joinable;已经执行完毕但没有 join 的线程依然是 joinable;detach 后的线程是不可以 join;
  • th.detach(); 将线程执行流从线程对象中分离出来,执行流结束自动释放资源;detach 后,线程 joinable() == false;如果线程本身已经 joinable == false() 了,抛出 system_error;
  • th.swap(other); th 和 other 交换;
  • std::this_thread::sleep_for(std::chrono::milliseconds(10)); 当前线程睡眠 (至少)10 毫秒(可能存在延迟),this_thread 是一个命名空间;
  • std::this_thread::get_id(); 获取当前线程id;
  • std::this_thread::yield(); 主动放弃执行,cpu 重新调度;
  • std::this_thread::sleep_until(tp); 当前线程睡眠到 tp 时间点;

互斥量

互斥量有 mutex、recursive_mutex、timed_mutex 和 recursive_timed_mutex。mutex 就是普通的互斥锁,一次只能一个人用(lock),用完之后 unlock 一下;recursive_mutex 是递归互斥锁,还是一次只能一个人,但是一个人可以 lock 两个或是更多次,而 lock 第一次 lock 获得锁,接着再 lock 就会阻塞自己(实际发生死锁了,O__O"…)。递归互斥锁的 lock 和 unlock 对依然需要匹配。

mutex/recursive_mutex

  • std::mutex m; 创建一个互斥量 m;
  • m.lock(); 获取锁,如果获取不到就被阻塞掉,直到可以获取到(不需要显式地被其他线程唤醒);如果发生 error 则抛出 std::system_error;
  • m.unlock(); 干完活了,释放锁 mutex;
  • bool b = m.try_lock(); 只是尝试获取锁,如果可以获取到就得到,如果获取不到也不阻塞;返回 true 或 false;
  • std::recursive_mutex rm; 创建一个递归互斥量 rm; 递归互斥量和 mutex 的差别是:rm 不需要重新获取锁,也就是第一次 lock() 获取到之后如果再次 lock() 不会重新获取(阻塞),而 mutex 在 lock() 之后再次 lock() 会造成死锁(也可以抛出 std::system_error 带 resource_deadlock_would_occur 错误码);

timed_mutex/recursive_timed_mutex

  • std::timed_mutex tm; 创建一个时间互斥量 tm;
  • tm.lock(); 获取锁,如果获取不到就被阻塞掉,直到可以获取到(不需要显示地被其他线程唤醒);如果发生 error 则抛出 std::system_error;
  • tm.unlock(); 释放锁,干完活了,释放 tm;
  • bool b = tm.try_lock(); 只是尝试获取锁,如果可以获取到就得到,如果获取不到也不阻塞;返回 true 或 false;
  • bool b = tm.try_lock_for(dur); dur 时间过后尝试锁住;
  • bool b = tm.try_lock_until(point); 到时间点 point 尝试获取锁;

lock_guard/unique_lock

mutex 的 lock()/unlock() 就像是 new/delete 一样,如果不注意很可能导致有 lock() 之后永远没有 unlock()。遵循 RAII 原则,c++ 提供了一个 mutex 的封装类: lock_guard 。

  • std::lock_guard<std::mutex> lock {m}; 构造 lock_guard 对象,能获取到 m 的锁则构造完成,否则阻塞构造;lock_guard 析构的时候释放 m 对应的锁;
  • lock_guard<mutex> lock {m, adopt_lock}; 将线程已经获取到的 m 的锁转让给 lock_guard ;
  • unique_lock<mutex> lock {m}; 和 lock_guard 类似,但是释放与获取 m 的锁更灵活; lock_guard 在生命周期内只掌握一把锁;

条件变量

future