现在计算机的发展,多核将成为一个趋势。
所以多线程编程也必然 将越来越流行。
不过,多线程编程同传统编程有很多不同。对计算机体系结构的不了解很可能会导致错误代码的产生。
比如说下面是一个多线程程序,线程1执行代码:
....
x=1;
y=1;
....
线程2执行代码
...
if(y==1){
if(x==0){
y=0;
}
}
....
假设x,y都是全局变量,而且这两个线程中所有其他代码都没有对数据x,y进行访问,那么请问上面代码执行完后,
变量x,y的值是多少呢?
很显然,最终x,y的值很可能都是1。但是还有一种可能就是最终x=1,y=0.
导致这个结果的第一个可能原因是对于编译器来说,在分别优化两个线程的代码时,可能会交换没有数据依赖关系的代码的顺序,比如线程1的代码可能回被优化成:
y=1;
x=1;
这对于传统单线程的代码是没有任何问题的。同样线程2中对x和y读取的顺序也可能被交换。
那么如果我们不让编译器进行优化,比如使用O0选项进行编译,是不是上面的代码最终结果就不可能是x=1,y=0了呢?
答案还是否定的,这个是因为现代计算机都采用了缓存(cache)结构, 所有对内存的访问都会首先通过缓存进行,只有缓存空间不够时,才会对内存进行访问。
所以对于上面的代码,当线程1将x,y赋值为1时,有可能对x的写操作只是写在缓存上(另一个处理器看不到),而对y进行写操作时,可能由于缓存空间不够,直接写入内存,结果被另一个处理器读取到。
所以即使上面代码没有经过任何优化,(或者我们直接书写汇编代码,按上面顺序进行访问),其结果也是不确定的。
那么如果要在多线程程序中事先类似上面代码的功能,我们需要如何操作呢?
有两种方法:
i)总是使用操作系统提供的线程间通讯函数进行线程间同步和通讯。
ii)将x,y定义成volatile变量,比如
volatile int x;
这两种方法都会导致编译出来的代码性能很大的降低,所以我们在写多线程代码时要注意尽量减少线程之间通讯的代码。