最近一个多月写的帖子比较杂,导致本系列又好久没更新了。结果又有网友在评论中催我了,搞得我有点囧。今天赶紧把多线程篇补上。上次聊操作系统
的时候,由于和OS有关的话题比较琐碎,杂七杂八说了一大堆。当时一看篇幅有点长,就把多进程和多线程的部分给留到后面了。<!-- program-think-->
★编译器
◇关于C运行库选项
先来说一个很基本的问题:关于C运行库(后面简称CRT:C Run-Time)的设置。本来不想聊这么低级的问题,但周围有好几个人都在这个地方吃过亏,所以还是讲一下。
大部分C++编译器都会自带有CRT(可能还不止一个)。某些编译器自带的CRT可能会根据线程的支持分为单线程CRT和多线程CRT两类。当你要进行多线程开发的时候,别忘了确保相关的C++工程项目使用的是多线程的CRT。否则会死得很难看。
尤其当你使用Visual C++创建工程项目,更加要小心。如果新建的工程项目是不含MFC的(包括Console工程和Win32工程),那工程的默认设置会是使用“单线程CRT”,如下图所示:
◇关于优化选项
“优化选项”是另一个很关键的编译器相关话题。有些编译器提供号称很牛X的优化选项,但是某些优化选项可能会有潜在的风险。编译器可能自作主张打乱执行指令的顺序,从而导致出乎意料的线程竞态问题(Race Condition,详细解释看“这里
”)。刘未鹏同学在“C++多线程内存模型
”里举了几个典型的例子,大伙儿可以去瞧一瞧。
建议只使用编译器常规的速度优化选项即可。其它那些花哨的优化选项,增加的效果未必明显,但是潜在的风险不小。实在不值得冒险。
以GCC为例:建议用-O2
选项即可(其实-O2
是一堆选项的集合),没必要冒险用-O3
(除非你有很充足的理由)。除了-O2
和-O3
之外,GCC还有一大坨(估计有上百个)其它的优化选项。如果你企图用当中的某个选项,一定要先把它的特性、可能的副作用都摸清楚,否则将来死都不知道怎么死的。
★线程库的选择
由于当前的C++ 03标准几乎没有涉及线程相关的内容(即使将来C++ 0x包含了线程的标准库,编译器厂商的支持在短期内也未必全面),所以在未来很长的一段时间,跨平台的多线程支持还是要依赖第三方库。所以线程库的选择是大大滴重要。下面大致介绍一下几个知名的跨平台线程库。
◇ACE
先说一下ACE这个历史悠久的库。如果你之前从未接触过它,先看“这里
”扫盲。从ACE的全称(Adaptive Communication Environment)来看,它应该是以“通讯”为主业。不过ACE对“多线程”这个副业的支持还是非常全面的,比如互斥锁(ACE_Mutex)、条件变量(ACE_Condition)、信号量(ACE_Semaphore)、栅栏(ACE_Barrier)、原子操作(ACE_Atomic_Op)等等。对某些类型比如ACE_Mutex还细分为线程读写锁(ACE_RW_Thread_Mutex)、线程递归锁(ACE_Recursive_Thread_Mutex)等等。
除了支持很全面,ACE还有另一个很明显的优点,就是对各种操作系统平台及其自带的编译器支持很好。包括一些老式的编译器(比如VC6),它也能够支持(此处所说的支持
,不光是能编译通过,而且要能稳定运行)。这个优点对于跨平台开发那是相当相当滴明显。
那缺点捏?由于ACE开工的年头很早(大概是上世纪九十年代中期),那会儿很多C++的老特性都还没出来(更别提新特性了),所以感觉ACE整个的风格比较老气,远不如boost那么时髦前卫。
◇boost::thread
boost::thread正好和ACE形成鲜明对照。这玩意貌似从boost
1.32版本开始引入,年头比ACE短。不过得益于boost里一帮大牛的支持,发展还是蛮快的。到目前的boost
1.38版本,也能够支持许多特性了(不过似乎没ACE多)。鉴于很多C++标准委员会的成员云集在boost社区中,随着时间的推
移,boost::thread终将成为C++线程的明日之星,前途无量啊!
boost::thread的缺点就是支持的编译器不够多,尤其是一些老式
编译器(很多boost的子库都有此问题,多半因为用了一些高级的模板语法)。这对于跨平台而言一个比较明显的问题。
◇wxWidgets
和QT
wxWidgets和QT都是GUI界面库,但是它们也都内置和对线程的支持。wxWidgets线程的简介可以看“这里
”,关于QT线程的简介可以看“这里
”。这两个库对线程的支持差不多,都提供了诸如mutex、condition、semaphore等常用的机制。不过特性没有ACE丰富。
◇如何权衡
对于开发GUI软件并已经用上了wxWidgets或者QT,那你可以直接用它们内置的线程库(前提是你只用到基本的线程功能)。由于它们内置的线程库,特性稍嫌单薄。万一你需要某高级的线程功能,那得考虑替换成boost::thread或ACE。
至于boost::thread和ACE的取舍,主要得看软件的需求了。如果你要支持的平台挺多挺杂,那建议选用ACE,以免碰上编译器不支持的问题。如果你只需要支持少数几个主流的平台(比如Windows、Linux、Mac),那建议用boost::thread。毕竟主流操作系统上的编译器,对boost的支持还是蛮好的。
★编程上的注意事项
其实多线程开发,需要注意的地方挺多的,我只能大致列几个印象比较深的注意事项。
◇关于volatile
说到多线程编程可能碰到的陷阱,那就不得不提到volatile
关键字。如果你对它还不甚了解,先看“这里
”扫盲一下。由于C++ 98和C++ 03标准都没有定义多线程的内存模型,而标准中也就volatile
和线程沾点儿边。结果导致C++社区中有相当多的口水都集中在volatile
身上(其中有不少C++大牛的口水)。有鉴于此,我这里就不再多啰嗦了。推荐几个大牛的文章:Andrei Alexandrescu
的文章“这里
”、还有Hans Boehm的文章“这里
”和“这里
”。大伙儿自个儿去拜读一下。
◇关于原子操作
有些同学光知道多个线程的竞争写
需要加锁,却不知道多个读
单个写
也需要保护。比如有某个整数int nCount = 0x01020304;在并发状态下,一个写线程去修改它的值nCount = 0x05060708;另一个读线程去获取该值。那么读线程有没有可能读取到一个“坏”的(比如0x05060304)数据捏?
数据是否坏掉,取决于对nCount的读和写是否属于原子操作。而这就依赖于很多硬件相关的因素了(包括CPU的类型、CPU的字长、内存对齐的字节数等)。在某些情况下,确实可能出现数据坏掉。
由于我们讨论的是跨平台的开发,天晓得将来你的代码会在啥样的硬件环境下执行。所以在处理类似问题的时候,还是要用第三方库提供的原子操作类/函数(比如ACE的Atomic_Op)来确保安全。
◇关于对象的析构
在之前的系列帖子“C++对象是怎么死的?
”里面,已经分别介绍了Win32平台和Posix平台下线程的非
自然死亡问题。由于上述几个跨平台的线程库底层还是要调用操作系统自带的线程API,所以大伙儿还是要尽最大努力确保所有
线程都能够自然死亡。
今天的话题就聊到这里,下一次聊多进程的话题。
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者编程随想
和本文原始地址:
http://program-think.blogspot.com/2009/04/cxx-cross-platform-develop-6-thread.html
分享到:
相关推荐
主要目的是作了一个中间程序转发网络消息,其实在网上有很多这样的程序, 比如跨平台的ACE,目前版本为5.6,如果从ACE开始学习网关,个人觉得挺费劲的, 我也曾经想用ACE编写网关程序,后来由于ACE的复杂性,...
主要目的是作了一个中间程序转发网络消息,其实在网上有很多这样的程序, 比如跨平台的ACE,目前版本为5.6,如果从ACE开始学习网关,个人觉得挺费劲的, 我也曾经想用ACE编写网关程序,后来由于ACE的复杂性,...
有一个庞大的库,库中包含很多可重用的代码和提供安全性、可移植性以及可自动垃圾回收等服务的执行环境。 JAVA特点: 简单性:摒弃了C++中易引发错误的特性,如指针和内存管理; 面向对象性:支持代码继承及...
在目前的跨平台GUI框架中,Qt成熟度最高,已经被一些大公司应用在关键产品中。由于Trolltech对Qt采用的dual license模式,该产品既可以从开源社区获得支持,又能够赚取足够的商业利润,因此其前景也令人比较有信心。...
java2级笔记 面向对象 java把所有的java... 可移植性 解释执行 多线程 解释执行 动态性 高性能 Applet的特点:嵌入HTML中,支持java的浏览器上运行 java与c++相比最突出的是跨平台性 不允许使用指针—健壮性
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...
可移植性:Java字节码可以在所有安装了JVM的设备上执行,从服务器到嵌入式系统,再到移动设备和桌面应用。 健壮性与高性能:Java通过垃圾回收机制确保内存的有效管理,同时也能通过JIT编译器优化来提升运行时性能...
它由Sun Microsystems(现在是Oracle Corporation)的James Gosling等人在1995年推出,被设计为一种简单、健壮、可移植、多线程、动态的语言。Java的主要特点和优势包括以下几个方面: 跨平台性(Write Once, Run ...