[并发并行]_[C/C++]_[C++标准库里的线程安全问题]
场景
1.写普通的程序时, 经常会使用cout来做输出, 每个进程只有一个控制台, 如果多线程调用cout时会出状况吗?
2.之所以研究cout会不会在并发下调用有问题, 是因为曾经有一个bug的崩溃点正好在cout处.
3.参考vc++的说明, iostream库的对象在并发write时是不会有问题的,原因是加了临界区,看osfinifo.c. 以下是对vc++针对stl库的线程安全的说明.
注: 虽然标准库说了支持cout并发, 但是在vs2010里出现过 ioinfo *pio = _pioinfo(fh); 这个 pio 为NULL的情况, 导致崩溃. 所以标准库实现也有BUG, 建议还是别用cout做并发输出.
osfinfo.c
int __cdecl __lock_fhandle (
int fh
)
{
ioinfo *pio = _pioinfo(fh);
int retval=TRUE;
/*
* Make sure the lock has been initialized.
*/
if ( pio->lockinitflag == 0 ) {
_mlock( _LOCKTAB_LOCK );
__TRY
if ( pio->lockinitflag == 0 ) {
if ( !InitializeCriticalSectionAndSpinCount( &(pio->lock), _CRT_SPINCOUNT )) {
/*
* Failed to initialize the lock, so return failure code.
*/
retval=FALSE;
}
pio->lockinitflag++;
}
__FINALLY
_munlock( _LOCKTAB_LOCK);
__END_TRY_FINALLY
}
if(retval)
{
EnterCriticalSection( &(_pioinfo(fh)->lock) );
}
return retval;
}
void __cdecl _unlock_fhandle (
int fh
)
{
LeaveCriticalSection( &(_pioinfo(fh)->lock) );
}
说明
1.以下线程安全的规则适用于标准C++库(除了shared_ptr 和 iostream类):
2.多线程读取一个单一的对象是线程安全. 比如给定一个对象A, 线程1 和线程2同时读取这个A对象是线程安全的.
3.如果一个对象正在被一个线程写, 那么所有对这个对象的读和写在其他线程里必须被保护起来(加锁). 比如, 给定一个对象A, 如果线程1 正在写入A, 那么必须阻止线程2读取或写入A.
4.一个线程对一个类型的实例的读写时, 另一个线程正对这个类型的另一个实例进行读写是安全的. 例如: 给定 A1和A2对象实例,它们属于同样类型A, 线程1中对A1进行写,而线程2中对A2进行读, 这种方式是安全的.
shared_ptr
1.多线程能同时对不同的shared_ptr对象进行读写, 即使这些对象是拥有共享所有权的复制品.
iostream 类
1.iostream 类和其他类遵守相同的规则, 除了一个例外, 它允许多线程进行写入对象. 比如, 线程1和线程2允许同时对cout进行写入. 这样也仅会导致输出混淆.
例子
- 以下例子验证了cout可允许多线程同时写, 并且std::vector可以同时读.
- 既然知道了标准库的对象特性, 这个问题自然知道原因. std::vector的多线程读写问题
// test-stl-thread-safety.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <vector>
static const int THREADCOUNT = 10;
DWORD WINAPI ThreadFunc(LPVOID param)
{
auto params = (std::vector<int>*)param;
for(int i = 0; i< 2000; ++i)
{
auto ite = params->begin();
for(; ite!= params->end();++ite)
std::cout << "Thread: " << GetCurrentThreadId() << " i: " << i << " params: " << *ite << std::endl;
}
return 0;
}
void TestConcurrentCout()
{
HANDLE hThread[THREADCOUNT];
std::vector<int> params;
params.push_back(0);
params.push_back(1);
params.push_back(2);
params.push_back(3);
params.push_back(4);
for(int i = 0; i< THREADCOUNT;++i)
{
hThread[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) ThreadFunc,
(LPVOID)¶ms,
0,
NULL);
}
for (int i = 0; i < THREADCOUNT; i++)
WaitForSingleObject(hThread[i], INFINITE);
}
int _tmain(int argc, _TCHAR* argv[])
{
TestConcurrentCout();
return 0;
}
参考
[并发并行]_[C/C++]_[C++标准库里的线程安全问题]的更多相关文章
- C++异常之七 标准库里的异常类
标准库里的异常类 C++标准提供了一组标准异常类,这些类以基类 Exception 开始,标准程序库抛出的所有异常,都派生于该基类,这些类构成如图所示的异常类的派生继承关系,该基类提供一个成员函数 w ...
- python基础教程_学习笔记14:标准库:一些最爱——re
标准库:一些最爱 re re模块包括对正則表達式的支持,由于以前系统学习过正則表達式,所以基础内容略过,直接看python对于正則表達式的支持. 正則表達式的学习,见<Mastering Reg ...
- python基础课程_学习笔记15:标准库:有些收藏夹——fileinput
标准库:有些收藏夹 fileinput 重要功能 性能 叙述性说明 input([files[,inplace[,backup]]) 便于遍历多个输入流中的行 filename() 返回当前文件的名称 ...
- python基础课程_学习笔记13:标准库:有些收藏夹——sys
标准库:有些收藏夹 sys sys这个模块可以让你访问和python解释器联系紧密的变量和函数. sys模块中一些重要的函数和变量 函数/变量 描写叙述 argv 命令行參数,包含脚本名称 exit( ...
- python基础课程_学习笔记20:标准库:有些收藏夹——os
标准库:有些收藏夹 os os模块为您提供访问多个操作系统服务特征. os和它的子模块os.path还包含一些用于检查.构造.删除文件夹和文件的函数,以及一些处理路径的函数. os模块中一些重要函数和 ...
- python基础教程_学习笔记19:标准库:一些最爱——集合、堆和双端队列
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/36201499 标准库:一些最爱 集合.堆和双端队 ...
- python基础教程_学习笔记18:标准库:一些最爱——shelve
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/36029981 标准库:一些最爱 shelve S ...
- Python3标准库:queue线程安全的FIFO实现
1. queue线程安全的FIFO实现 queue模块提供了一个适用于多线程编程的先进先出(FIFO,first-in,first-out)数据结构,可以用来在生产者和消费者线程之间安全地传递消息或其 ...
- C++标准库里自带的数值类型和字符串互相转换函数
需要包含头文件 #include <string> 数值类型转成string类型: string to_string(int val); string to_string(unsigned ...
随机推荐
- python之系统命令
subprocess执行系统命令 call:执行命令,返回状态码 #!/usr/bin/env python # _*_ coding:utf-8 _*_ __Author__ = 'KongZhaG ...
- gridview导出数据,如果为0开头,丢失0解决方案
1.protected void GridView1_RowDataBound( object sender, GridViewRowEventArgs e ) { if (e.Row.Row ...
- Mysql使用binlog恢复数据解决误操作问题的两种方法
为保证没有其他参数配置影响,重新安装配置了一台最小化安装的CentOS7虚拟机 1. 基础知识 安装mysql5.6数据库Mysql binlog初步理解 2. 配置mysql 开启binlog.修 ...
- 使用mac版思维导图软件MindNode
下载地址 http://pan.baidu.com/s/1hq3fUVq 思维导图又叫心智图,是表达发射性思维的有效的图形思维工具 ,它简单却又极其有效,是一种革命性的思维工具.思维导图运用图文并重的 ...
- iOS设计模式 - 命令
iOS设计模式 - 命令 原理图 说明 命令对象封装了如何对目标执行指令的信息,因此客户端或调用者不必了解目标的任何细节,却仍可以对他执行任何已有的操作.通过把请求封装成对象,客户端可以把它参数化并置 ...
- mysql用户创建及授权
一. 创建用户: 命令:CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 说明:username - 你将创建的用户名, host - 指 ...
- Spring-IOC bean 创建过程中的 ObjectFactory
AbstractBeanFactory中doGetBean方法里有一段拿到RootBeanDefinition后,实例化该bean的方法 // Create bean instance. if (mb ...
- 【洛谷】【线段树】P3353 在你窗外闪耀的星星
[题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...
- TensorFlow函数(九)tf.add_to_collection()、tf.get_collection() 和 tf.add_n()
tf.add_to_collection(name, value) 此函数将元素添加到列表中 参数: name:列表名.如果不存在,创建一个新的列表 value:元素 tf.get_collectio ...
- Python学习之路 (五)爬虫(四)正则表示式爬去名言网
爬虫的四个主要步骤 明确目标 (要知道你准备在哪个范围或者网站去搜索) 爬 (将所有的网站的内容全部爬下来) 取 (去掉对我们没用处的数据) 处理数据(按照我们想要的方式存储和使用) 什么是正则表达式 ...