c++11多线程记录3: 数据争用和Mutex的使用
https://www.youtube.com/watch?v=3ZxZPeXPaM4 学习视频
数据争用
简单来说就是存在多个线程同时对某个共同的对象进行读写(至少有一个线程在做写操作),造成读取这个对象时的结果不可预测
如下
int num = 0;
void func(int &v)
{
for (int i = 0; i < 100000; ++i)
{
num = num + 1;
v++;
}
}
int main()
{
int v = 0;
std::vector<std::thread> ts;
for (int i = 0; i < 100; ++i)
{
ts.push_back(std::thread(func, std::ref(v)));
}
for (int i = 0; i < 100; ++i)
{
ts[i].join();
}
std::cout << num << ", " << v << std::endl;
return 0;
}
cout结果并不是10 000 000, 10 000 000
使用Mutex控制对象的读写
在对象的读写操作之前调用mutex::lock即可(记得不需要持有对象时调用mutex::unlock)
...
std::mutex mu;
void func()
{
...
mu.lock();
num += 1;
v += 1;
mu.unlock();
}
...
std::lock_guard
在mutex的lock-unlock块里如果抛出异常,那么unlock就不会被调用(或者忘记调用unlock也是有可能的),
这时可以考虑使用lock_guard:
...
{
std::lock_guard<std::mutex> guard(mu);
v++;
num++;
}
...
我感觉应该是lock_guard内部将会持有mutex,然后在析构函数里尝试调用mutex的unlock方法
读写控制的对象有没有完全被锁定
针对上面的例子,有一个全局变量num,和一个局部变量v,虽然在各个子线程里都用mutex进行了读写控制;
但是在主线程里并没有,仍然可以在main里面随意的处理这两个共享对象;
处理方法就是将要保护的资源对象和mutex绑定在一起,保证每次使用资源对象前必须通过mutex
如下:
class LogFile {
std::mutex m_mutex;
ofstream f;
LogFile() {
f.open(...);
}
void shared_print(string id, int value) {
std::lock_guard<mutex> guard(m_mutex);
f << id << ", " << value << endl;
}
// ofstream &getStream() { return f; }
}
上面这个例子,切记不能将LogFile的f对象暴露出来,就像最后一行注释那样
当然如果返回的是ofstream是没问题的;
还有一些其它情况可能“意外”暴露LogFile::f,如下:
void LogFile::processf(void fun(ofstream&))
{
fun(this->f);
}
这里就“不小心”将f对象引用传递给了某个函数fun,在fun里,LogFile::f就失去了mutex的保护
小结
- 使用mutex来控制资源对象的读写
- 不要将内部资源对象暴露出Wrapper类
- 注意接口设计的合理性
c++11多线程记录3: 数据争用和Mutex的使用的更多相关文章
- c++11多线程记录2:线程管理
线程没有调用join和detach thread对象必须调用join或者detach,否则程序会终止 例如: void func() { std::cout << "hello, ...
- c++11多线程记录0
两种并发编程模型 多进程 进程间通信常用的几种方式: 文件 管道 消息队列 多线程 一个进程中存在的多个线程,通常通过共享内存来通信,(说的非常非常粗俗,就是通过类似"全局变量"的 ...
- c++11多线程记录6:条件变量(condition variables)
https://www.youtube.com/watch?v=13dFggo4t_I视频地址 实例1 考虑这样一个场景:存在一个全局队列deque,线程A向deque中推入数据(写),线程B从deq ...
- c++11多线程记录5: Unique Lock和延时初始化
https://www.youtube.com/user/BoQianTheProgrammer 视频网址 Unique Lock unique_lock和lock_guard类似,都是mutex的w ...
- c++11多线程记录4:死锁
简单示例 举个例子,桌上有一支笔和一张纸,小A和小B都要拿到纸笔写字 小A拿了笔,小B拿了纸,这时就形成了死锁(两人都不愿意让出纸笔). 其实只要稍加控制就可以避免这种情况:规定必须先拿到纸再能去尝试 ...
- c++11多线程记录1 -- std::thread
启动一个线程 话不多说,直接上代码 void func(); int main() { std::thread t(func); //这里就开始启动线程了 t.join(); // 必须调用join或 ...
- c++11 多线程 -- 基本使用
c++11 多线程 – 基本使用 前言:这篇文章仅针对没有使用过c++11线程库的童鞋来高速入门,也是自己的一个简单记录,内容比較基础. 1.线程的基本使用 2.相互排斥量 3.条件变量 4.原子变量 ...
- C++11多线程教学(一)
本篇教学代码可在GitHub获得:https://github.com/sol-prog/threads. 在之前的教学中,我展示了一些最新进的C++11语言内容: 1. 正则表达式(http://s ...
- C# 实现的多线程异步Socket数据包接收器框架
转载自Csdn : http://blog.csdn.net/jubao_liang/article/details/4005438 几天前在博问中看到一个C# Socket问题,就想到笔者2004年 ...
随机推荐
- Numpy | 05 创建数组
ndarray 数组除了可以使用底层 ndarray 构造器来创建外,也可以通过以下几种方式来创建. 一.numpy.empty numpy.empty 方法用来创建一个指定形状(shape).数据类 ...
- java 面向对象2
1. 类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体. 玩具模型是类: 玩具是对象: ★局部变量和成员变量的区别: 区别一:定义的位置不同 定义在类中的变量是成员变量 定义在方法中或 ...
- Zookeeper在分布式架构中的应用
Zookeeper 是一个高性能.高可靠的分布式协调系统,是 Google Chubby 的一个开源实现.Zookeeper 能够为分布式应用提供一致性服务,提供的功能包括:配置维护.域名服务.分布式 ...
- Visual Studio调试窗口一闪而过的解决方法
小编在用vs写程序时,经常碰到调试窗口一闪而过的情况,以至于根本无法查看程序输出结果. 为了解决这个问题,可以在程序的末尾加上一个系统调用语句: int main(){ printf("我不 ...
- JSX 简介
JSX 简介 考虑如下变量声明: const element = <h1>Hello, world!</h1>; 这个有趣的标签语法既不是字符串也不是HTML. 它被称为JSX ...
- Python逆向(二)—— pyc文件结构分析
一.前言 上一节我们知道了pyc文件是python在编译过程中出现的主要中间过程文件.pyc文件是二进制的,可以由python虚拟机直接执行的程序.分析pyc文件的文件结构对于实现python编译与反 ...
- 【小盘子看源码-MyBatis-1】MyBatis配置文件的加载流程
众所周知,Mybatis有一个全局的配置,在程序启动时会加载XML配置文件,将配置信息映射到org.apache.ibatis.session.Configuration类中,例如如下配置文件. &l ...
- UE运行sas配置-WIN10
1.在UE中配置SAS运行的工具: UE--高级---用户工具--工具配置 在命令行输入"D:\soft\SASHome\SASFoundation\9.4\sas.exe" -c ...
- 【转】Spring Boot @Condition 注解,组合条件你知道吗
原文:https://www.cnblogs.com/FraserYu/p/11280420.html 上一篇文章 你应该知道的 @ConfigurationProperties 注解的使用姿势,这一 ...
- Anaconda更新失败简单解决[CondaHTTPError: HTTP 000 CONNECTION FAILED for url]
问题:conda无法安装更新,报错内容如下:参考链接:conda httperror http none none for url none Anaconda更新失败 conda create -n ...