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

来源:本站
导读:目前正在解读《C语言多线程中变量累加问题的分析》的相关信息,《C语言多线程中变量累加问题的分析》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《C语言多线程中变量累加问题的分析》的详细说明。
简介:本文主要是对C语言多线程中变量累加问题进行分析,感性趣的朋友可以参考下。

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

/*********************************************************************** 版权所有 (C)2015, Zhou Zhaoxiong。** 文件名称:MultipleThread_1.c* 文件标识:无* 内容摘要:多线程中的变量值问题* 其它说明:无* 当前版本:V1.0* 作    者:Zhou Zhaoxiong* 完成日期:20151117***********************************************************************/#include <stdio.h>#include <stdlib.h>#include <pthread.h>// 重定义数据类型typedef signed   int    INT32;typedef unsigned int    UINT32;// 宏定义#define THREAD_NUM     100              // 线程个数// 全局变量UINT32 g_iTestInteger = 0;// 函数声明void ProcessTask(void *pParam);/*********************************************************************** 功能描述:主函数* 输入参数:无* 输出参数:无* 返 回 值:无* 其它说明:无* 修改日期        版本号     修改人            修改内容* -------------------------------------------------------------------* 20151117       V1.0     Zhou Zhaoxiong      创建***********************************************************************/INT32 main(){    pthread_t MultiHandle  = 0;      // 多线程句柄    pthread_t SingleHandle = 0;     // 单线程句柄    UINT32    iLoopFlag    = 0;    INT32     iRetVal      = 0;  // 创建线程函数的返回值    // 循环创建线程    for (iLoopFlag = 0; iLoopFlag < THREAD_NUM; iLoopFlag ++)    {        iRetVal = pthread_create(&MultiHandle, NULL, (void * (*)(void *))(&ProcessTask), (void *)iLoopFlag);        if (0 != iRetVal)        {            printf("Create ProcessTask %d failed!n", iLoopFlag);            return -1;        }    }    // 打印全局变量的值    printf("In main, TestInteger = %dn", g_iTestInteger);    return 0;   }/********************************************************************** * 功能描述: 处理线程 * 输入参数: pParam-线程编号 * 输出参数: 无 * 返 回 值: 无 * 其它说明: 无 * 修改日期            版本号            修改人           修改内容 * ----------------------------------------------------------------------*  20151117           V1.0          Zhou Zhaoxiong       创建 ************************************************************************/void ProcessTask(void *pParam){    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

~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread

In main, TestInteger = 99

~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread

In main, TestInteger = 99

~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread

In main, TestInteger = 98

~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread

In main, TestInteger = 99

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

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

/*********************************************************************** 版权所有 (C)2015, Zhou Zhaoxiong。** 文件名称:MultipleThread_2.c* 文件标识:无* 内容摘要:多线程中的变量值问题* 其它说明:无* 当前版本:V1.0* 作    者:Zhou Zhaoxiong* 完成日期:20151117***********************************************************************/#include <stdio.h>#include <stdlib.h>#include <pthread.h>// 重定义数据类型typedef signed   int    INT32;typedef unsigned int    UINT32;// 宏定义#define THREAD_NUM     100              // 线程个数// 全局变量UINT32 g_iTestInteger = 0;// 函数声明void ProcessTask(void *pParam);/*********************************************************************** 功能描述:主函数* 输入参数:无* 输出参数:无* 返 回 值:无* 其它说明:无* 修改日期        版本号     修改人            修改内容* -------------------------------------------------------------------* 20151117       V1.0     Zhou Zhaoxiong      创建***********************************************************************/INT32 main(){    pthread_t MultiHandle  = 0;      // 多线程句柄    pthread_t SingleHandle = 0;     // 单线程句柄    UINT32    iLoopFlag    = 0;    INT32     iRetVal      = 0;  // 创建线程函数的返回值    // 循环创建线程    for (iLoopFlag = 0; iLoopFlag < THREAD_NUM; iLoopFlag ++)    {        iRetVal = pthread_create(&MultiHandle, NULL, (void * (*)(void *))(&ProcessTask), (void *)iLoopFlag);        if (0 != iRetVal)        {            printf("Create ProcessTask %d failed!n", iLoopFlag);            return -1;        }    }    // 打印全局变量的值    printf("In main, TestInteger = %dn", g_iTestInteger);    return 0;   }/********************************************************************** * 功能描述: 处理线程 * 输入参数: pParam-线程编号 * 输出参数: 无 * 返 回 值: 无 * 其它说明: 无 * 修改日期            版本号            修改人           修改内容 * ----------------------------------------------------------------------*  20151117           V1.0          Zhou Zhaoxiong       创建 ************************************************************************/void ProcessTask(void *pParam){    g_iTestInteger ++;    printf("TestInteger = %dn", 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

In main, TestInteger = 98

TestInteger = 99

TestInteger = 74

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

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

/*********************************************************************** 版权所有 (C)2015, Zhou Zhaoxiong。** 文件名称:MultipleThread_3.c* 文件标识:无* 内容摘要:多线程中的变量值问题* 其它说明:无* 当前版本:V1.0* 作    者:Zhou Zhaoxiong* 完成日期:20151117***********************************************************************/#include <stdio.h>#include <stdlib.h>#include <pthread.h>// 重定义数据类型typedef signed   int    INT32;typedef unsigned int    UINT32;// 宏定义#define THREAD_NUM     100              // 线程个数// 全局变量UINT32 g_iTestInteger = 0;// 函数声明void ProcessTask(void *pParam);void Sleep(UINT32 iCountMs);/*********************************************************************** 功能描述:主函数* 输入参数:无* 输出参数:无* 返 回 值:无* 其它说明:无* 修改日期        版本号     修改人            修改内容* -------------------------------------------------------------------* 20151117        V1.0   Zhou Zhaoxiong       创建***********************************************************************/INT32 main(){    pthread_t MultiHandle  = 0;      // 多线程句柄    pthread_t SingleHandle = 0;     // 单线程句柄    UINT32    iLoopFlag    = 0;    INT32     iRetVal      = 0;  // 创建线程函数的返回值    // 循环创建线程    for (iLoopFlag = 0; iLoopFlag < THREAD_NUM; iLoopFlag ++)    {        iRetVal = pthread_create(&MultiHandle, NULL, (void * (*)(void *))(&ProcessTask), (void *)iLoopFlag);        if (0 != iRetVal)        {            printf("Create ProcessTask %d failed!n", iLoopFlag);            return -1;        }    }    Sleep(1000);   // 休息1s    // 打印全局变量的值    printf("In main, TestInteger = %dn", g_iTestInteger);    return 0;   }/********************************************************************** * 功能描述: 处理线程 * 输入参数: pParam-线程编号 * 输出参数: 无 * 返 回 值: 无 * 其它说明: 无 * 修改日期            版本号            修改人           修改内容 * ----------------------------------------------------------------------*  20151117           V1.0          Zhou Zhaoxiong       创建 ************************************************************************/void ProcessTask(void *pParam){    g_iTestInteger ++;}/*********************************************************************** 功能描述: 程序休眠* 输入参数: iCountMs-休眠时间(单位:ms)* 输出参数: 无* 返 回 值: 无* 其它说明: 无* 修改日期          版本号       修改人              修改内容* ------------------------------------------------------------------* 20151117          V1.0    Zhou Zhaoxiong          创建********************************************************************/void Sleep(UINT32 iCountMs){    struct timeval t_timeout = {0};    if (iCountMs < 1000)    {        t_timeout.tv_sec = 0;        t_timeout.tv_usec = iCountMs * 1000;    }    else    {        t_timeout.tv_sec = iCountMs / 1000;        t_timeout.tv_usec = (iCountMs % 1000) * 1000;    }    select(0, NULL, NULL, NULL, &t_timeout);   // 调用select函数阻塞程序}

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

~/zhouzhaoxiong/zzx/MultipleThread> gcc -g -o MultipleThread MultipleThread_3.c -lpthread

~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread

In main, TestInteger = 100

~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread

In main, TestInteger = 100

~/zhouzhaoxiong/zzx/MultipleThread> MultipleThread

In main, TestInteger = 100

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

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

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

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

提醒:《C语言多线程中变量累加问题的分析》最后刷新时间 2024-03-14 00:59:13,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《C语言多线程中变量累加问题的分析》该内容的真实性请自行鉴别。