选择虚拟机环境介入多线程编程是一个好的选择

多核处理,并行设计已经成为了计算机发展不可阻挡的趋势之一。越来越多的技术人员开始关注多线程程序设计。但是选择什么样的环境来介入多线程程序设计往往是一个比较头疼的问题。应该说,目前的许多环境并没有为多线程建立良好的模型,例如C和C++。为此,人们试图在这种环境中通过添加库的方式为其加入多线程的功能。但是,这显然是不合适的,实际上许多的时候,程序库根本不能解决所有的问题,我们真正需要的是一种将多线程纳入其规范体系之内的环境。

 

我们在C/C++中编写多线程程序依靠的往往不是严谨的定义与标准约束,而是经验占据了主要的部分。我们的多线程代码并没有较广的适用性,而是在严重的依赖于编译器文档中提供的编译器的提供的内存模型信息。并且您需要时刻小心的处理编译器Optimization带来的影响。这使得多线程代码在这种语言下变得非常难看。我们不仅仅要考虑操作系统的问题,处理器体系的问题,甚至要考虑各种编译器的支持问题。书写过多线程库的技术人员也许会对漫天飞舞的Macro Definition感到一种前所未有的满足感,而维护人员则叫苦不迭。当然,你可能说,这种事情永远不会在你身上发生,因为你为Microsoft工作,你只为Windows写程序,你只使用Visual C++编译器,并且你永远不会使用除了Intel之外的处理器。

 

拿一个例子来说[1]

 

Thread 1:
if (x == 1) ++y

 

Thread2:
if (y == 1) ++x;

 

假设x和y一开始均初始化为0,那么这个程序会有数据竞争吗?从上述来看也许不会吧,如果他们就是像写的那样执行的话,但是有一个问题,编译器也许会对单线程优化为:

 

Thread 1:
++y; if (x != 1) --y;

 

Thread 2:
++x; if (y != 1) --x;

 

可能这种优化有些傻(或者说,根本不是优化),但是仅仅就一个例子而言已经足够了。也就是,编译器不会对你的代码负责,并且也没有必要,因为编译器本来就没有违反标准。标准中对线程的行为几乎只字未提。

 

文献[1]中另外有一个例子:

 

struct { int a:17; int b:15 } x;

 

实际上,没有一款处理器可以直接处理17位的读写工作,因此类似于x.a = 42之类的操作实际上是这样完成的:

 

{
 tmp = x; // Read both fields into
 // 32-bit variable.
 tmp &= ~0x1ffff; // Mask off old a.
 tmp |= 42;
 x = tmp; // Overwrite all of x.
}

 

而这在多线程环境下就引入了潜在的竞争!

 

还有几个非常经典的问题那就是volatile是什么东西?sequence point又是什么东西?答案是,没有人说得清楚。

 

好了,你可能说,那怎么解决这些问题呢。根本的答案应该是,在新标准中慎重考虑这些事情!考虑共享内存多线程模式下的内存模型以及线程行为。众所周之,ISO C++委员会是一个官僚组织,就像OpenGL对于DirectX一样,任何事情的决定都是缓慢而困难的。尤其对于有大批大批遗留代码的C++更是如此!举个例子,我们可不可以像java或者.net一样将volatile读写赋予某种语义呢,例如acquire,release或者total order(虽然这很不可思议),看起来不错,但是不要忘记了,大批大批的volatile存在于遗留的代码中,这种memory fence的引入会让原有的代码在重新编译之后产生很大的性能下降(你知道interlockedXxx以及类似操作会多花多少个时钟周期吗?很惊人的哦),这是人们不能接受的,因此他们正在讨论引入atomic library从另一个角度解决这个问题。

 

因此,我们的结论是,如果你希望入手多线程编程,应当找到一个内存模型完备(基本完备,我的意思是)的环境来入手,虚拟机环境(Java,.NET)是一个不错的选择。当然,我们应该时刻跟踪C++的发展,为将来做好准备,毕竟它是一个有着悠久历史的,有着大批拥趸的,非常有魅力的语言!

 

附:C++ 0x标准中关于内存模型的讨论参见:

 

http://www.open-std.org/ 网站上WG21的以下文档:

 

N1680, N1777, N1876, N1911, N1942, N1947, N2010, N2016, N2052, N2075, N2138, N2153, N2171, N2176, N2177, N2197, N2237, N2300, N2334, N2338, N2359, N2360, N2361, N2429, N2480, N2492, N2493, N2556, N2664

 

(注:上述文献追踪已经更新到2008年6月)

 

参考文献:
[1] Hans-J. Boehm,Threads Cannot be Implemented as a Library,Internet Systems and Storage Laboratory,HP Laboratories Palo Alto,November 12, 2004

[2] Java memory model specification.

posted @ 2008-07-28 15:59  TW-刘夏  阅读(2337)  评论(8编辑  收藏  举报