C language/Atom/compile, do you really understand?

Source: Internet
Author: User

When it comes to atoms, code similar to the following may be seen by everyone.

#include <stdio.h>#include<pthread.h>intCNT =0;void* Mythread (void*Arg) {        inti;  for(i=0;i<500000000; i++) CNT++; returnNULL;}intMain () {pthread_t id, id2; Pthread_create (&ID, NULL, mythread, NULL); Pthread_create (&id2, NULL, mythread, NULL);        Pthread_join (ID, NULL);        Pthread_join (Id2, NULL); printf ("cnt =%d\n", CNT); return 0;}

I think most people know that the result may not be 1000000000.

Test it.

Linux-p94b:/tmp/testhere # gcc Test1.c-lpthreadlinux-p94b:/tmp/testhere # for ((i=0;i<10;i++));d O./a.out; donecnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 958925625cnt = 1 000000000cnt = 1000000000cnt = 1000000000

But do you really know what's wrong? What if I compile it and optimize it?

Linux-p94b:/tmp/testhere # Gcc-o2 Test1.c-lpthreadlinux-p94b:/tmp/testhere # for ((i=0;i<10;i++));d O./a.out; donecnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000

The speed of the operation suddenly became fast, and seemed to have been 1 billion.

Here, the Mythread CNT has been optimized to CNT + = 500000000 Since adding 500 million times

Well, of course it is, but it seems that there are some differences in the way we tried to test the atom, the same code, not the same compilation, but brought different results.

In fact, the reason is that we do not write a good code here, we did not express our original meaning, we are hoping that CNT really added 500 million times. So what do we do? Actually very good, in the definition of CNT before adding a volatile, then here for CNT's self-addition will not be optimized. Many times, why we optimize before and after the results of the optimization is not the same, often because the person writing code does not understand the program optimization rules. At the time of the last company, I would like to leave the time to give you a training, talk about the optimization of C language, at the same time said that we usually write the so-called unintentional reliance on the compilation of the alleged garbage code, but until left, I still did not do this training.

We added the volatile test,

Linux-p94b:/tmp/testhere # Gcc-o2 Test1.c-lpthreadlinux-p94b:/tmp/testhere # for ((i=0;i<10;i++));d O./a.out; donecnt = 635981117cnt = 675792826cnt = 522700646cnt = 593410055cnt = 544306380cnt = 630888304cnt = 580539893cnt = 6293600 72cnt = 555570127

We add a volatile before the CNT definition, the effect is even more obvious, because it is really self-added 500 million times, causing problems more opportunities. Wouldn't it be possible to have a 1 billion chance of not adding volatile and optimizing the compilation before?

The first thing we need to understand is that the cnt++ here is not an atomic operation, there is a possibility of scheduling at any time.

500 million times too much, we take a self-add 1 times as an example to illustrate that two threads are only 1 times, and expected the result is 2.

Cnt++ has at least three instructions in the generic processor, which we write with a pseudo-assembly.

CNT-to-reg//To load CNT from memory to register Reg

Reg+1-reg//Register REG ADD 1

Reg, CNT//write Reg content to memory

  

So

(thread 1) CNT--Reg

(thread 1) reg+1-reg

(thread 1) reg-, CNT

(thread 2) CNT--Reg

(thread 2) reg+1-reg

(thread 2) reg-, CNT

Ideally, we think that the implementation of the processor is the above, the result CNT value is 2.

But assuming that the schedule has occurred, the order of instruction execution is not like this, if it becomes the following

(thread 1) CNT--Reg

(thread 1) reg+1-reg

(thread 2) CNT--Reg

(thread 2) reg+1-reg

(thread 2) reg-, CNT

(thread 1) reg-, CNT

We'll figure it out again.

CNT = 0, reg arbitrary

(thread 1) CNT--Reg

CNT = 0, reg = 0

(thread 1) reg+1-reg

CNT = 0, Reg = 1

Dispatched here, Reg = 1 is saved and is valid after re-dispatching, and CNT does not control

After dispatch

CNT = 0, reg arbitrary

(thread 2) CNT--Reg

CNT = 0, reg = 0

(thread 2) reg+1-reg

CNT = 0, Reg = 1

(thread 2) reg-, CNT

CNT = 1, reg = 1

The dispatch here again, Reg will restore the previous saved 1, and CNT will not have any changes

So before executing the next instruction,

CNT = 1, reg = 1

(thread 1) reg-, CNT

CNT = 1, reg = 1

  

We can see that the result is 1, not 2, this is the result of non-atomic operation, in fact, before optimization to CNT + = 500000000 itself still has this problem, but it is difficult to observe.

Although X + + is not an atom, we can use locks to artificially create "atoms," such as mutual exclusion.

  

#include <stdio.h>#include<pthread.h>volatile intCNT =0;p thread_mutex_t Mutex=Pthread_mutex_initializer;void* Mythread (void*Arg) {        inti;  for(i=0;i<500000000; i++) {Pthread_mutex_lock (&mutex); CNT++; Pthread_mutex_unlock (&mutex); }        returnNULL;}intMain () {pthread_t id, id2; Pthread_create (&ID, NULL, mythread, NULL); Pthread_create (&id2, NULL, mythread, NULL);        Pthread_join (ID, NULL);        Pthread_join (Id2, NULL); printf ("cnt =%d\n", CNT); return 0;}

Test it.

Linux-p94b:/tmp/testhere # Gcc-o2 Test1.c-lpthreadlinux-p94b:/tmp/testhere # for ((i=0;i<10;i++));d O./a.out; donecnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000cnt = 1000000000

  

C language/Atom/compile, do you really understand?

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.