上一篇《C++11 并发指南二(std::thread 详解)》中主要讲到了 std::thread 的一些用法,并给出了两个小例子,本文将介绍 std::mutex 的用法。

Mutex 又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 <mutex> 头文件中,所以如果你需要使用 std::mutex,就必须包含 <mutex> 头文件。

<mutex> 头文件介绍

Mutex 系列类(四种)

  • std::mutex,最基本的 Mutex 类。
  • std::recursive_mutex,递归 Mutex 类。
  • std::time_mutex,定时 Mutex 类。
  • std::recursive_timed_mutex,定时递归 Mutex 类。

Lock 类(两种)

  • std::lock_guard,与 Mutex RAII 相关,方便线程对互斥量上锁。
  • std::unique_lock,与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。

其他类型

  • std::once_flag
  • std::adopt_lock_t
  • std::defer_lock_t
  • std::try_to_lock_t

函数

  • std::try_lock,尝试同时对多个互斥量上锁。
  • std::lock,可以同时对多个互斥量上锁。
  • std::call_once,如果多个线程需要同时调用某个函数,call_once 可以保证多个线程对该函数只调用一次。

std::mutex 介绍

下面以 std::mutex 为例介绍 C++11 中的互斥量用法。

std::mutex 是C++11 中最基本的互斥量,std::mutex 对象提供了独占所有权的特性——即不支持递归地对 std::mutex 对象上锁,而 std::recursive_lock 则可以递归地对互斥量对象上锁。

std::mutex 的成员函数

  • 构造函数,std::mutex不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。
  • lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:(1). 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。(2). 如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
  • unlock(), 解锁,释放对互斥量的所有权。
  • try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况,(1). 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量。(2). 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。

下面给出一个与 std::mutex 的小例子(参考

#include <iostream>       // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex volatile int counter(); // non-atomic counter
std::mutex mtx; // locks access to counter void attempt_10k_increases() {
for (int i=; i<; ++i) {
if (mtx.try_lock()) { // only increase if currently not locked:
++counter;
mtx.unlock();
}
}
} int main (int argc, const char* argv[]) {
std::thread threads[];
for (int i=; i<; ++i)
threads[i] = std::thread(attempt_10k_increases); for (auto& th : threads) th.join();
std::cout << counter << " successful increases of the counter.\n"; return ;
}

std::recursive_mutex 介绍

std::recursive_mutex 与 std::mutex 一样,也是一种可以被上锁的对象,但是和 std::mutex 不同的是,std::recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁),来获得对互斥量对象的多层所有权,std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),可理解为 lock() 次数和 unlock() 次数相同,除此之外,std::recursive_mutex 的特性和 std::mutex 大致相同。

std::time_mutex 介绍

std::time_mutex 比 std::mutex 多了两个成员函数,try_lock_for(),try_lock_until()。

try_lock_for 函数接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞住(与 std::mutex 的 try_lock() 不同,try_lock 如果被调用时没有获得锁则直接返回 false),如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。

try_lock_until 函数则接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。

下面的小例子说明了 std::time_mutex 的用法(参考)。

#include <iostream>       // std::cout
#include <chrono> // std::chrono::milliseconds
#include <thread> // std::thread
#include <mutex> // std::timed_mutex std::timed_mutex mtx; void fireworks() {
// waiting to get a lock: each thread prints "-" every 200ms:
while (!mtx.try_lock_for(std::chrono::milliseconds())) {
std::cout << "-";
}
// got a lock! - wait for 1s, then this thread prints "*"
std::this_thread::sleep_for(std::chrono::milliseconds());
std::cout << "*\n";
mtx.unlock();
} int main ()
{
std::thread threads[];
// spawn 10 threads:
for (int i=; i<; ++i)
threads[i] = std::thread(fireworks); for (auto& th : threads) th.join(); return ;
}

std::recursive_timed_mutex 介绍

和 std:recursive_mutex 与 std::mutex 的关系一样,std::recursive_timed_mutex 的特性也可以从 std::timed_mutex 推导出来,感兴趣的同鞋可以自行查阅。 ;-)

std::lock_guard 介绍

与 Mutex RAII 相关,方便线程对互斥量上锁。例子(参考):

#include <iostream>       // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::lock_guard
#include <stdexcept> // std::logic_error std::mutex mtx; void print_even (int x) {
if (x%==) std::cout << x << " is even\n";
else throw (std::logic_error("not even"));
} void print_thread_id (int id) {
try {
// using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
std::lock_guard<std::mutex> lck (mtx);
print_even(id);
}
catch (std::logic_error&) {
std::cout << "[exception caught]\n";
}
} int main ()
{
std::thread threads[];
// spawn 10 threads:
for (int i=; i<; ++i)
threads[i] = std::thread(print_thread_id,i+); for (auto& th : threads) th.join(); return ;
}

std::unique_lock 介绍

与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。例子(参考):

#include <iostream>       // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock std::mutex mtx; // mutex for critical section void print_block (int n, char c) {
// critical section (exclusive access to std::cout signaled by lifetime of lck):
std::unique_lock<std::mutex> lck (mtx);
for (int i=; i<n; ++i) {
std::cout << c;
}
std::cout << '\n';
} int main ()
{
std::thread th1 (print_block,,'*');
std::thread th2 (print_block,,'$'); th1.join();
th2.join(); return ;
}

好了,本文暂时讲到这里,还剩下 std::try_lock,std::lock,std::call_once 三个函数没有讲到,留在下一篇博客中讲吧 ;-)

C++11 并发指南三(std::mutex 详解)的更多相关文章

  1. 【C/C++开发】C++11 并发指南三(std::mutex 详解)

    本系列文章主要介绍 C++11 并发编程,计划分为 9 章介绍 C++11 的并发和多线程编程,分别如下: C++11 并发指南一(C++11 多线程初探)(本章计划 1-2 篇,已完成 1 篇) C ...

  2. C++11 并发指南三(std::mutex 详解)(转)

    转自:http://www.cnblogs.com/haippy/p/3237213.html 上一篇<C++11 并发指南二(std::thread 详解)>中主要讲到了 std::th ...

  3. C++11 并发指南五(std::condition_variable 详解)

    前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread,std::mut ...

  4. C++11 并发指南五(std::condition_variable 详解)(转)

    前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread,std::mut ...

  5. 【转】C++11 并发指南五(std::condition_variable 详解)

    http://www.cnblogs.com/haippy/p/3252041.html 前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三 ...

  6. C++11 并发指南二(std::thread 详解)

    上一篇博客<C++11 并发指南一(C++11 多线程初探)>中只是提到了 std::thread 的基本用法,并给出了一个最简单的例子,本文将稍微详细地介绍 std::thread 的用 ...

  7. C++11 并发指南二(std::thread 详解)(转)

    上一篇博客<C++11 并发指南一(C++11 多线程初探)>中只是提到了 std::thread 的基本用法,并给出了一个最简单的例子,本文将稍微详细地介绍 std::thread 的用 ...

  8. 【C/C++开发】C++11 并发指南二(std::thread 详解)

    上一篇博客<C++11 并发指南一(C++11 多线程初探)>中只是提到了 std::thread 的基本用法,并给出了一个最简单的例子,本文将稍微详细地介绍 std::thread 的用 ...

  9. C++11 并发指南六(atomic 类型详解三 std::atomic (续))

    C++11 并发指南六( <atomic> 类型详解二 std::atomic ) 介绍了基本的原子类型 std::atomic 的用法,本节我会给大家介绍C++11 标准库中的 std: ...

随机推荐

  1. 2018-02-27 "Literate Programming"一书摘记之一

    书到后才发现是Knuth的论文集, 第一篇就在网上: Computer programming as an art (1974). 其中"Taste and Style"(品味和风 ...

  2. 如何将web项目部署到Ubuntu服务器上

    情景回顾: 前几天在下本着人道主义原则帮我老师的一个朋友做了个小网页,(啥人道不人道的,主要是给钱了),做完之后本来是想偷懒直接把网页扔给他自己部署去吧,结果让我帮忙部署一下,得,偷懒也偷不成了,搞吧 ...

  3. Windows下更新 npm 和 nodejs

    一.更新npm // 将npm更新到最新版本 npm install npm@latest -g 二.更新nodejs 1. 首先通过 where node 命令找到nodejs的安装路径 2. 然后 ...

  4. 程序员简单打造一个灵活智能的自动化运维系统C#实例程序

    你是一个程序员,被派去管理公司500台计算机.这些机器可能需要执行一些自动化任务,一台台手动操作会把你累死.重复性的工作还是交给电脑处理,怎么解决这个问题呢?一个自动化的运维系统是必须的.自己实现的好 ...

  5. List基础操作

    /** * List基础操作 * Created by zhen on 2018/11/14. */ object ListDemo { def main(args: Array[String]) { ...

  6. 洗礼灵魂,修炼python(50)--爬虫篇—基础认识

    爬虫 1.什么是爬虫 爬虫就是昆虫一类的其中一个爬行物种,擅长爬行. 哈哈,开玩笑,在编程里,爬虫其实全名叫网络爬虫,网络爬虫,又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者 ...

  7. python编程的简洁代码

    1.列表间元素操作 L1 = [1,3,5,]L2 = [2,5,3,1,8]x = set(L1)y = set(L2)#差集print(y - x)#交集print(y&x)#并集prin ...

  8. 使用 PsPing & PaPing 进行 TCP 端口连通性测试

    PsPing & PaPing 介绍 通常,我们测试数据包能否通过 IP 协议到达特定主机时,都习惯使用 ping 命令.工作时 ping 向目标主机发送一个 IMCP Echo 请求的数据包 ...

  9. Linux regulator framework(1) - 概述【转】

    转自蜗窝科技:http://www.wowotech.net/pm_subsystem/regulator_framework_overview.html 1. 前言 Regulator,中文名翻译为 ...

  10. php报错 【 Call to undefined function imagecreatetruecolor()】

    刚才在写验证码的时候,发现报错,然后排查分析了一下,原来是所用的php版本(PHP/5.3.13)没有开启此扩展功能. 进入php.ini 找到extension=php_gd2.dll ,将其前面的 ...