Analysis of variable accumulation in multiple threads in C Language

Source: Internet
Author: User

Analysis of variable accumulation in multiple threads in C Language

Q: What is the value of g_iTestInteger printed by the main function in the following program?

/*************************************** * ******************************** All Rights Reserved (C) 2015, Zhou Zhaoxiong. ** File name: MultipleThread_1.c * File ID: none * Content Abstract: variable value in multithreading * Other Instructions: none * Current version: V1.0 * OPERATOR: Zhou Zhaoxiong * completion date: 20151117 *************************************** * *******************************/# include
  
   
# Include
   
    
# Include
    
     
// Redefine the Data Type typedef signed int INT32; typedef unsigned int UINT32; // macro definition # define THREAD_NUM 100 // Number of threads // global variable UINT32 g_iTestInteger = 0; // function declaration void ProcessTask (void * pParam ); /*************************************** * ******************************** function description: main function * input parameter: none * output parameter: none * return value: none * Other Description: No * modified date version number modifier modified content * optional * 20151117 V1.0 Zhou Zhaoxion G creation ************************************** * *******************************/INT32 main () {pthread_t MultiHandle = 0; // multithreading handle pthread_t SingleHandle = 0; // single thread handle UINT32 iLoopFlag = 0; INT32 iRetVal = 0; // create the return value of the thread function // create the thread cyclically 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 !, ILoopFlag); return-1 ;}// print the global variable value printf (In main, TestInteger = % d, g_iTestInteger); return 0 ;} /*************************************** * ******************************** function description: processing thread * input parameter: pParam-thread Number * output parameter: none * return value: none * Other description: no * modified date version number modifier modified content * found * 20151117 V1.0 Zhou Zhaoxiong create *********************** **************************************** * *******/void ProcessTask (void * pParam) {g_iTestInteger ++ ;}
    
   
  

The functions of the above program are relatively simple, that is, to create 100 identical threads, accumulate the value of g_iTestInteger in the thread, and print the value of g_iTestInteger in the main function.

When we see this program, we may say that the value of the g_iTestInteger variable should be 100, because each thread adds g_iTestInteger once. Okay, let's run the program first and check the output.

Upload the program to a Linux machine and perform the following operations:

~ /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

To most people's expectation, the value of the g_iTestInteger variable is not only 100, but also not a fixed value. Here, I only run the program five times. You can run the program several times to check whether the result is 100.

So why is the result not 100? To find the cause, print the value of the g_iTestInteger variable after the "g_iTestInteger ++;" code, as shown in the following code:

/*************************************** * ******************************** All Rights Reserved (C) 2015, Zhou Zhaoxiong. ** File name: MultipleThread_2.c * File ID: none * Content Abstract: variable value in multithreading * Other Instructions: none * Current version: V1.0 * OPERATOR: Zhou Zhaoxiong * completion date: 20151117 *************************************** * *******************************/# include
  
   
# Include
   
    
# Include
    
     
// Redefine the Data Type typedef signed int INT32; typedef unsigned int UINT32; // macro definition # define THREAD_NUM 100 // Number of threads // global variable UINT32 g_iTestInteger = 0; // function declaration void ProcessTask (void * pParam ); /*************************************** * ******************************** function description: main function * input parameter: none * output parameter: none * return value: none * Other Description: No * modified date version number modifier modified content * optional * 20151117 V1.0 Zhou Zhaoxion G creation ************************************** * *******************************/INT32 main () {pthread_t MultiHandle = 0; // multithreading handle pthread_t SingleHandle = 0; // single thread handle UINT32 iLoopFlag = 0; INT32 iRetVal = 0; // create the return value of the thread function // create the thread cyclically 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 !, ILoopFlag); return-1 ;}// print the global variable value printf (In main, TestInteger = % d, g_iTestInteger); return 0 ;} /*************************************** * ******************************** function description: processing thread * input parameter: pParam-thread Number * output parameter: none * return value: none * Other description: no * modified date version number modifier modified content * found * 20151117 V1.0 Zhou Zhaoxiong create *********************** **************************************** * *******/void ProcessTask (void * pParam) {g_iTestInteger ++; printf (TestInteger = % d, g_iTestInteger );}
    
   
  

Re-upload the program, compile and execute the program as follows:

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
Test integer = 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

We can see that the value of the g_iTestInteger variable does not increase sequentially. From this we can see that the execution time of these 100 threads is divided successively ~ If 100 is their numbers, it is not necessarily said that thread 10 should be executed after thread 9. In addition, when the g_iTestInteger variable value is printed in the main function, there may be threads executing (from the program output results, it is true), so the printed value is not 100, instead, it is less than 100. We can guess that the value range of g_iTestInteger is [1,100].

To print the g_iTestInteger value after the thread completes execution, we can sleep the program for a period of time after the thread is created, and then print the variable value. The following code is used:

/*************************************** * ******************************** All Rights Reserved (C) 2015, Zhou Zhaoxiong. ** File name: MultipleThread_3.c * File ID: none * Content Abstract: variable value in multithreading * Other Instructions: none * Current version: V1.0 * OPERATOR: Zhou Zhaoxiong * completion date: 20151117 *************************************** * *******************************/# include
  
   
# Include
   
    
# Include
    
     
// Redefine the Data Type typedef signed int INT32; typedef unsigned int UINT32; // macro definition # define THREAD_NUM 100 // Number of threads // global variable UINT32 g_iTestInteger = 0; // function declaration void ProcessTask (void * pParam); void Sleep (UINT32 iCountMs ); /*************************************** * ******************************** function description: main function * input parameter: none * output parameter: none * return value: none * Other Description: No * modified date version number modifier content *-------------------------------------------------------------------* 20151117 V1.0 Zhou Zhaoxiong create *********************************** * **********************************/INT32 main () {pthread_t MultiHandle = 0; // multithreading handle pthread_t SingleHandle = 0; // single thread handle UINT32 iLoopFlag = 0; INT32 iRetVal = 0; // create the return value of the thread function // create the thread cyclically for (iLoopFlag = 0; iLoopFlag <THREAD_NUM; iLoopFlag ++) {iRetVal = pthread_create (& MultiHandle, NULL, (void * (*) (void *) (& ProcessTask), (vo Id *) iLoopFlag); if (0! = IRetVal) {printf (Create ProcessTask % d failed !, ILoopFlag); return-1 ;}} Sleep (1000); // rest 1 s // print the global variable value printf (In main, TestInteger = % d, g_iTestInteger ); return 0 ;} /*************************************** * ******************************** function description: processing thread * input parameter: pParam-thread Number * output parameter: none * return value: none * Other description: no * modified date version number modifier modified content * found * 20151117 V1.0 Zhou Zhaoxiong create *********************** **************************************** * *******/void ProcessTask (void * pParam) {g_iTestInteger ++ ;} /*************************************** * ******************************** function description: program sleep * input parameter: iCountMs-sleep time (unit: ms) * output parameter: none * return value: none * Other Instructions: no * modified date version number modifier modified content * found * 20151117 V1.0 Zhou Zhaoxiong create *********************** **************************************** * ***/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, & t_timeout); // call the select function blocking program}
    
   
  

Re-upload the program, compile and execute the program as follows:

~ /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.

As you can see, the program runs multiple times, and the value of g_iTestInteger is always 100. It seems that "don't eat hot tofu", we will print the variable value after all the threads are executed.

Through the above analysis, we can draw the following conclusions:

First, in a multi-threaded program, do not add or subtract the same global variable at the same time, so the execution result may not be what we want.

Second, multithreading is not omnipotent. The original intention of creating multithreading is to execute many operations that are unrelated or have little relevance in parallel. If some operations have strong coupling relationships (such as adding 1 to the g_iTestInteger variable in this example), it is better to put them in a single thread for sequential execution.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.