[并发并行]_[C/C++]_[C++标准库里的线程安全问题]
2017-01-14 15:55
639 查看
场景
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) ); }
说明
以下线程安全的规则适用于标准C++库(除了shared_ptr 和 iostream类):1.多线程读取一个单一的对象是线程安全. 比如给定一个对象A, 线程1 和线程2同时读取这个A对象是线程安全的.
2.如果一个对象正在被一个线程写, 那么所有对这个对象的读和写在其他线程里必须被保护起来(加锁). 比如, 给定一个对象A, 如果线程1 正在写入A, 那么必须阻止线程2读取或写入A.
3.一个线程对一个类型的实例的读写时, 另一个线程正对这个类型的另一个实例进行读写是安全的. 例如: 给定 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; }
参考
Thread Safety in the Standard C++ Library相关文章推荐
- [并发并行]_[C/C++]_[C++标准库里的线程安全问题]
- 如果静态方法里面没有存取静态字段的话, 就没有并发的线程安全的问题...(这句话对吗?)
- 线程安全与并发安全探究(三)--servlet多线程并发问题
- Java Web并发访问的线程安全问题
- 深入理解线程 以及线程并发的线程安全问题及处理方法
- C++并发实战12:线程安全的queue
- SpringMVC和Struts2并发访问时的线程安全问题
- Java Web并发访问的线程安全问题
- 如何处理线程并发时产生的线程安全问题(Runnable和Thread)
- [并发并行]_[C/C++]_[使用线程本地存储Thread Local Storage(TLS)-win32线程和pthread线程比较]
- Java并发(1) i++的线程安全问题
- [并发并行]_[C/C++]_[使用线程本地存储Thread Local Storage(TLS)调用复制文件接口的案例]
- 同步异步-线程并发安全问题
- C++并发实战12:线程安全的queue
- 进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结
- Netty : writeAndFlush的线程安全及并发问题
- Netty : writeAndFlush的线程安全及并发问题
- 解决线程并发安全问题
- Java Web并发访问的线程安全问题
- 进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结