https://www.youtube.com/user/BoQianTheProgrammer 视频网址

Unique Lock

unique_lock和lock_guard类似,都是mutex的wrapper类,但是前者更加灵活

  • lock_guard没有unlock方法,unique_lock可以调用unlock
  • unique_lock可以延时调用lock方法,lock_guard不行
  • unique_lock不可复制、可移动,lock_guard不可复制、不可移动
// 1
...
std::unique_lock<std::mutex> locker(mu);
g_num ++;
locker.unlock();
... // 2
...
std::unique_lock<std::mutex> locker(mu, std::defer_lock);
...
locker.lock();
g_num++;
locker.unlock();
...
locker.lock();
g_num++;
locker.unlock();
... // 3
...
std::unique_lock<std::mutex> locker2 = std::move(locker);

unique_lock并不能取代lock_guard

unique_lock的灵活性是有代价的,灵活的同时其本身所占空间也越大(时间性能上不了解)

有时候并不需要unique_lock的那些灵活性,只要用lock_guard即可

Lasy Initialization

先看下面一段代码

class LogFile {
std::mutex _mu;
ofstream _f;
public:
LogFile() {
_f.open("log.txt");
}
void func(string id, int v) {
std::unique_lock<mutex> locker(_mu);
_f << id << ", " << v << endl;
}
}

打印日志的类,在构造函数里打开log.txt

但是有可能自始至终都没有打印过日志(调用func),那么_f.open就没有必要调用

可以考虑在func中调用_f.open,如下

class LogFile {
std::mutex _mu;
ofstream _f;
public:
LogFile() {
// _f.open("log.txt");
}
void func(string id, int v) {
if (!_f.is_open()) {
_f.open("log.txt");
}
std::unique_lock<mutex> locker(_mu);
_f << id << ", " << v << endl;
}
}

线程安全

这时就要考虑LogFile::func的线程安全问题(针对资源对象_f)),按照前面的方法,通过mutex来控制_f的使用

class LogFile {
std::mutex _mu_open;
ofstream _f;
public:
LogFile() { }
void func(string id, int v) {
if (!_f.is_open()) {
std::unique_lock<mutex> locker(_mu_open);
_f.open("log.txt");
}
...
}
}

上面这段代码并没有做到线程安全。场景假设:

线程A和线程B同时进到 if (_f.is_open()),这时文件并没有打开过,所以都通过了if判断,

接着A,B都会调用获取mutex,假设A先获取,然后A调用open打开文件,然后释放mutex,

接着B就会获取mutex,然后会再调用一次open。

两次打开一个文件!

不仅仅_f.open需要同步,_f.is_open也需要同步:

...
std::unique_lock<mutex> locker2(_mu_open);
if (_f.is_open()) {
_f.open("log.txt");
}
locker2.unlock();
...

但是这时又会有另外一个问题,每次func函数被调用时都会有一次mutex获取的行为,一定程度上会影响程序的并发性

std::once_flag和std::call_once

针对上面那个问题,c++提供了std::once_flag来解决:

class LogFile {
std::once_flag _flag;
ofstream _f;
public:
LogFile() { }
void func(string id, int v) {
std::call_once(_flag, [&](){_f.open("log.txt");});
...
}
}

上面代码里的lambda函数仅会被一个线程调用一次!

c++11多线程记录5: Unique Lock和延时初始化的更多相关文章

  1. c++11多线程记录0

    两种并发编程模型 多进程 进程间通信常用的几种方式: 文件 管道 消息队列 多线程 一个进程中存在的多个线程,通常通过共享内存来通信,(说的非常非常粗俗,就是通过类似"全局变量"的 ...

  2. c++11多线程记录6:条件变量(condition variables)

    https://www.youtube.com/watch?v=13dFggo4t_I视频地址 实例1 考虑这样一个场景:存在一个全局队列deque,线程A向deque中推入数据(写),线程B从deq ...

  3. c++11多线程记录4:死锁

    简单示例 举个例子,桌上有一支笔和一张纸,小A和小B都要拿到纸笔写字 小A拿了笔,小B拿了纸,这时就形成了死锁(两人都不愿意让出纸笔). 其实只要稍加控制就可以避免这种情况:规定必须先拿到纸再能去尝试 ...

  4. c++11多线程记录3: 数据争用和Mutex的使用

    https://www.youtube.com/watch?v=3ZxZPeXPaM4 学习视频 数据争用 简单来说就是存在多个线程同时对某个共同的对象进行读写(至少有一个线程在做写操作),造成读取这 ...

  5. c++11多线程记录2:线程管理

    线程没有调用join和detach thread对象必须调用join或者detach,否则程序会终止 例如: void func() { std::cout << "hello, ...

  6. c++11多线程记录1 -- std::thread

    启动一个线程 话不多说,直接上代码 void func(); int main() { std::thread t(func); //这里就开始启动线程了 t.join(); // 必须调用join或 ...

  7. c++11 多线程 -- 基本使用

    c++11 多线程 – 基本使用 前言:这篇文章仅针对没有使用过c++11线程库的童鞋来高速入门,也是自己的一个简单记录,内容比較基础. 1.线程的基本使用 2.相互排斥量 3.条件变量 4.原子变量 ...

  8. 【转】C++ 11 并发指南一(C++ 11 多线程初探)

    引言 C++ 11自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些C++ 11的新特性,算是记录一下自己学到的东西吧,和大家共勉. 相信Linux程序员都用过Pthrea ...

  9. C++11 并发指南一(C++11 多线程初探)

    引言 C++11 自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些 C++11 的新特性,今后几篇博客我都会写一些关于 C++11 的特性,算是记录一下自己学到的东西吧, ...

随机推荐

  1. MySQL InnoDB 群集–在Windows上设置InnoDB群集

    InnoDB集群最需要的功能之一是Windows支持,我们现在已将其作为InnoDB Cluster 5.7.17预览版 2的一部分提供.此博客文章将向您展示如何在MS Windows 10上运行In ...

  2. 使用Visual Studio Code编辑Processing

    最近想弄Sublime Text 3写Processing,但由于各种不知名原因导致无法编译,就想着换自去年以来超火的VScode试一下,还真给我试成功了. 1.下载https://code.visu ...

  3. FPGA综合的约束

    近日发现,有些逻辑电路的综合时间约束和布局布线约束相差太大时,难以布通.此时,应该选择尽量接近的时钟约束.

  4. CSS样式的引入方式

    test.css div{ color:yellow; } 在html中引入 <link href="test.css" type="text/css" ...

  5. gitlab 上传代码

    #生成公钥ssh-keygen -t ed25519 -C "xxx@tianwang.com"#拷贝公钥pbcopy < ~/.ssh/id_ed25519.pub 在网页 ...

  6. [后渗透]获取到 Meterpreter 之后的操作

    sysinfo 列出受控主机的系统信息 ls 列出目标主机的文件和文件夹信息 use priv 加载特权提升扩展模块,来扩展meterpreter库 ps 显示所有运行进程以及关联的用户账户 gets ...

  7. 解决vue视图不渲染

    动态添加对象属性 //声明var travelMainVueObj;travelMainVueObj = new Vue({ "el" : "#portletConten ...

  8. Mysql 排序规则选择

    排序规则:是指对指定字符集下不同字符的比较规则.其特征有以下几点: 1. 两个不同的字符集不能有相同的排序规则 2. 两个字符集有一个默认的排序规则 3. 有一些常用的命名规则.如_ci结尾表示大小写 ...

  9. C#-DllImport 路径问题

    原文:C# DllImport 相对路径无法找到dll DllImport DLL查找顺序:1.应用程序所在目录2.Windows目录和Windows\System32目录3.环境变量目录 只需要你把 ...

  10. js比较时间大于6个月

    //mons是比较的月数,如 2019-02-01 14:27:08 - 2019-08-01 14:27:08 function compareTime(mons,stTime,endTime){ ...