天天看点

C语言多线程中变量累加问题的分析

问题:请问下面程序中,main函数打印出的g_iTestInteger变量的值是多少?

以上程序的功能比较简单,就是创建100个相同的线程,在线程中对g_iTestInteger的值进行累加,然后在main函数中打印g_iTestInteger的值。

看到这个程序,大家可能会说g_iTestInteger变量的值应该是100,因为每个线程都对g_iTestInteger加了1次。好吧,我们先运行程序,看下打印出来的结果是多少。

我们将程序上传到Linux机器上,然后执行如下操作:

~/zhouzhaoxiong/zzx/MultipleThread> gcc -g -o MultipleThread MultipleThread_1.c -lpthread ~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread In main, TestInteger = 99 In main, TestInteger = 98

出乎大多数人的意料,g_iTestInteger变量的值不但不是100,而且不是固定的值。在这里,我只是运行了五次程序,大家可以多运行几次,看结果会不会是100。

那么,为什么结果不是100呢?为了查找原因,我们在“g_iTestInteger ++;”代码之后将g_iTestInteger变量的值打印出来,如下代码所示:

重新上传程序,编译并执行,如下:

TestInteger = 1 TestInteger = 3 TestInteger = 2 TestInteger = 4 TestInteger = 5 TestInteger = 6 TestInteger = 26 TestInteger = 7 TestInteger = 8 TestInteger = 9 TestInteger = 10 TestInteger = 11 TestInteger = 12 TestInteger = 13 TestInteger = 27 TestInteger = 15 TestInteger = 16 TestInteger = 17 TestInteger = 18 TestInteger = 19 TestInteger = 20 TestInteger = 21 TestInteger = 22 TestInteger = 23 TestInteger = 24 TestInteger = 25 TestInteger = 14 TestInteger = 28 TestInteger = 29 TestInteger = 30 TestInteger = 31 TestInteger = 32 TestInteger = 33 TestInteger = 34 TestInteger = 35 TestInteger = 36 TestInteger = 37 TestInteger = 38 TestInteger = 39 TestInteger = 40 TestInteger = 41 TestInteger = 42 TestInteger = 43 TestInteger = 44 TestInteger = 45 TestInteger = 49 TestInteger = 47 TestInteger = 48 TestInteger = 46 TestInteger = 50 TestInteger = 54 TestInteger = 55 TestInteger = 56 TestInteger = 57 TestInteger = 52 TestInteger = 53 TestInteger = 58 TestInteger = 59 TestInteger = 60 TestInteger = 61 TestInteger = 62 TestInteger = 63 TestInteger = 51 TestInteger = 64 TestInteger = 65 TestInteger = 66 TestInteger = 67 TestInteger = 68 TestInteger = 69 TestInteger = 70 TestInteger = 71 TestInteger = 72 TestInteger = 73 TestInteger = 100 TestInteger = 75 TestInteger = 76 TestInteger = 77 TestInteger = 78 TestInteger = 79 TestInteger = 80 TestInteger = 81 TestInteger = 82 TestInteger = 83 TestInteger = 84 TestInteger = 85 TestInteger = 86 TestInteger = 87 TestInteger = 88 TestInteger = 89 TestInteger = 90 TestInteger = 91 TestInteger = 92 TestInteger = 93 TestInteger = 94 TestInteger = 95 TestInteger = 96 TestInteger = 97 TestInteger = 98 TestInteger = 99 TestInteger = 74

可以看到,g_iTestInteger变量的值并不是顺序增加的。由此可以看出,这100个线程的执行时间有先后之分,如果按照1~100为它们编号的话,并不一定说10号线程要在9号线程之后执行。除此之外,在main函数中打印g_iTestInteger变量值的时候,也许还有线程在执行(从程序输出结果来看,确实如此),因此打印出的值不是100,而是小于100的一个数。我们可以猜想,g_iTestInteger的值的范围是[1, 100]。

为了等线程执行完成之后再打印g_iTestInteger的值,我们可以在线程创建完成之后让程序休眠一段时间,然后再打印变量值。如下代码所示:

~/zhouzhaoxiong/zzx/MultipleThread> gcc -g -o MultipleThread MultipleThread_3.c -lpthread In main, TestInteger = 100

可以看到,程序运行了多次,g_iTestInteger的值始终是100。看来,“心急吃不得热豆腐”,我们要等所有线程都全部执行完成之后,再来打印变量值。

通过以上分析,我们可以得出以下结论:

第一,在多线程程序中,尽量不要同时对同一个全局变量执行加减等操作,这样执行之后的结果很有可能不是我们想要的。

第二,多线程不是万能的,创建多线程的初衷,是要并行地执行很多互不关联或关联度很小的操作。如果某些操作有很强的耦合关系(如本例中的对g_iTestInteger变量加1),那么放到一个单线程里面顺序执行更好。

继续阅读