In the comments in the previous blog titled "problems caused by concurrent thread execution", several friends (Jin Se's fifty-string, Kevin-moon, etc.) mentioned the issue of using volatile to declare variables, first of all, I would like to thank them for their guidance. In the past, I only knew that the volatile keyword was to notify the compiler to read data from its memory every time during operations on this variable. Do not optimize it, however, I do not know the specific process. Read an article todayArticleThe relationship between compilation and C just mentioned this issue, so I will record it and ask for more advice.
First, let's look at a simpleProgramThat is, assign values to the Buf Array Using TMP. The program is very simple, so no comments are added:
1 # Include < Stdio. h >
2
3 Unsigned Char TMP;
4
5 Unsigned Char Buf [ 3 ];
6
7 Int Main ()
8 {
9 Buf [ 0 ] = TMP;
10 Buf [ 1 ] = TMP;
11 Buf [ 2 ] = TMP;
12
13 Return 0 ;
14 }
15
Compile it first:
Huangwei @ Ubuntu :~ /Desktop $ GCC volatile. C-o a. Out-G
Huangwei @ Ubuntu :~ /Desktop $ objdump-Ds A. Out
1 Buf [ 0 ] = TMP ;
2 8 0483b7 : 0f B6 05 18 A0 04 08 Movzbl 0x804a018, % eax
3 8 0483be : A2 19 A0 04 08 MoV % Al, 0x804a019
4 Buf [ 1 ] = TMP ;
5 8 0483c3 : 0f B6 05 18 A0 04 08 Movzbl 0x804a018, % eax
6 8 0483ca : A2 1A A0 04 08 MoV % Al, 0x804a01a
7 Buf [ 2 ] = TMP ;
8 8 0483cf : 0f B6 05 18 A0 04 08 Movzbl 0x804a018, % eax
9 8 0483d6 : A2 1B A0 04 08 MoV % Al, 0x804a01b
10
The Assembly generated aboveCodeWe can see that every time the program extracts the TMP value from the 0x804a018 address, and then assigns the value to the Buf array element, this code is clearly in line with our expectations. Next, let the compiler optimize the compilation. Let's take a look at the differences in the compiled code:
Huangwei @ Ubuntu :~ /Desktop $ GCC volatile. C-o B. Out-g-o
Huangwei @ Ubuntu :~ /Desktop $ objdump-Ds B. Out
1 Buf [ 0 ] = TMP ;
2 8 0483b7 : 0f B6 05 18 A0 04 08 Movzbl 0x804a018, % eax
3 8 0483be : A2 19 A0 04 08 MoV % Al, 0x804a019
4 Buf [ 1 ] = TMP ;
5 8 0483c3 : A2 1A A0 04 08 MoV % Al, 0x804a01a
6 Buf [ 2 ] = TMP ;
7 8 0483c8 : A2 1B A0 04 08 MoV % Al, 0x804a01b
8
Compared with the above code, we can find that the TMP value is obtained from the memory only when the value is assigned for the first time in the program, all of them directly assign the initial TMP value saved in register Al to the Buf array element. In this case, there is no problem under normal circumstances, but the problem of concurrent thread execution is reached. Let's take a closer look at this problem. After the thread extracts the TMP value from the memory for the first time, the operating system schedules the execution of the TMP value and schedules the execution of another thread. The thread modifies the TMP value. Next, after the original thread resumes execution, the initial value of TMP is stored in its register Al. the value assigned to TMP is still the initial value of TMP. In this way, the data is not synchronized.
Next, we will use volatile to declare the TMP variable. The others will be the same as the above program:
VolatileUnsignedCharTMP;
Let's let the compiler optimize the compilation:
Huangwei @ Ubuntu :~ /Desktop $ GCC volatile. C-o C. Out-g-o
Huangwei @ Ubuntu :~ /Desktop $ objdump-Ds C. Out
1 Buf [ 0 ] = TMP ;
2 8 0483b7 : 0f B6 05 18 A0 04 08 Movzbl 0x804a018, % eax
3 8 0483be : A2 19 A0 04 08 MoV % Al, 0x804a019
4 Buf [ 1 ] = TMP ;
5 8 0483c3 : 0f B6 05 18 A0 04 08 Movzbl 0x804a018, % eax
6 8 0483ca : A2 1A A0 04 08 MoV % Al, 0x804a01a
7 Buf [ 2 ] = TMP ;
8 8 0483cf : 0f B6 05 18 A0 04 08 Movzbl 0x804a018, % eax
9 8 0483d6 : A2 1B A0 04 08 MoV % Al, 0x804a01b
10
From the assembly code above, we can see that every time the program extracts the TMP value from the memory, and then assigns the value to the Buf array element, this will meet the expectation. The above is just a personal idea. If it is wrong, please make an axe. Thank you.