The program below has different behaviors with different option levels. When I compile it with -O3, it will never terminate. when I compile it with -O0, it will always terminate very soon.
#include <stdio.h>
#include <pthread.h>
void *f(void *v) {
    int *i = (int *)v;
    *i = 0;
    printf("set to 0!\n");
    return NULL;
}
int main() {
    const int c = 1;
    int i = 0;
    pthread_t thread;
    void *ptr = (void *)&c;
    while (c) {
        i++;
        if (i == 1000) {
            pthread_create(&thread, NULL, &f, ptr);
        }
    }
    printf("done\n");
}
This is the result of running it with different optimization flags.
username@hostname:/src$  gcc -O0 main.c -o main
username@hostname:/src$  ./main 
done
set to 0!
set to 0!
username@hostname:/src$  gcc -O3 main.c -o main
username@hostname:/src$  ./main 
set to 0!
set to 0!
set to 0!
set to 0!
set to 0!
set to 0!
^C
username@hostname:/src$ 
The answer given by the professor's slide is like this:
- Will it always terminate? 
- Depends of gcc options 
- With –O3 (all optimisations): no 
Why?
- The variable cis likely to stay local in a register, hence it will not be shared.
Solution « volatile »
Thank you for your replies. I now realize that volatile is a keyword in C. The description of the volatile keyword:
A
volatilespecifier is a hint to a compiler that an object may change its values in ways not specified by the language so that aggressive optimizations must be avoided.
According to my understanding, there is a shared register that stores the c value when we use -O3 flag. So the main thread and sub-thread will share it. In this case, if a sub-thread modifies c to 0, the main thread will get 0 when it wants to read c to compare in the while(c) statement. Then, the loop stops.
There is no register storing c  that can be shared by the main thread and sub-threads when we use -O0 flag. Though the c is modified by a sub-thread, this change may not be written to memory and just be stored in a register, or it is written to memory while the main thread just uses the old value which is read and saved in a register. As a result, the loop is infinite.
If I declared the c value with const: const volatile int c = 1;, the program will terminate finally even if we compiled it with -O3. I guess all threads will read c from the main memory and write back to the main memory if they change the c value.
I know, according to the specifications or rules about C language, we are not allowed to modify a value that is declared by the const keyword. But I don't understand what is un behavior.
I wrote a test program:
#include "stdio.h"
int main() {
    const int c = 1;
    int *i = &c;
    *i = 2;
    printf("c is : %d\n", c);
}
output
username@hostname:/src$ gcc test.c -o test
test.c: In function ‘main’:
test.c:9:14: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
    9 |     int *i = &c;
      |              ^
username@hostname:/src$ ./test
c is : 2
username@hostname:/src$ 
The result is 2 which means a variable declared with the const can be modified but this behavior is not suggested, right?
I also tried changing the judgment condition. If it is changed to while (1){ from while(c){, the loop will be an infinite one no matter using -O0 or -O3
This program is not a good one as it violates the specifications or rules of C language. Actually it comes from the lecture about software security.
Can I just understand like this? All threads share the same register storing c when we compile the program with -O0.
While the value c is in un-shared registers, so main thread is not informed when sub-threads modify value c when we use -O3. Or, while(c){ is replaced by while(1){ when we use -O3 so the loop is infinite.
I know this question can be solved easily if I check the generated assembly code. But I am not good at it.
 
     
     
    