Why gcc isn't optimizing the global variable? - c

I am trying to understand the behavior of volatile and compiler optimization in C through an example.
For this, I referred:
Where to use volatile?
Why is volatile needed in C?
https://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming
All of the above posts have at least one answer related to signal handler so for this, I have written a simple code to actually implement and observe the behavior in Linux just for understanding.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
int counter = 0;
void *thread0_func(void *arg)
{
printf("Thread 0\n");
while(1)
{
}
return NULL;
}
void *thread1_func(void *arg)
{
printf("Thread 1\n");
while(counter == 0)
{
printf("Counter: %d\n", counter);
usleep(90000);
}
return NULL;
}
void action_handler(int sig_no)
{
printf("SigINT Generated: %d\n",counter);
counter += 1;
}
int main(int argc, char **argv)
{
pthread_t thread_id[2];
struct sigaction sa;
sa.sa_handler = action_handler;
if(sigaction(SIGINT, &sa, NULL))
perror("Cannot Install Sig handler");
if(pthread_create(&thread_id[0], NULL, thread0_func, NULL))
{
perror("Error Creating Thread 0");
}
if(pthread_create(&thread_id[1], NULL, thread1_func, NULL))
{
perror("Error Creating Thread 0");
}
else
{
}
while(1)
{
if(counter >= 5)
{
printf("Value of Counter is more than five\n");
}
usleep(90000);
}
return (0);
}
This code is just for learning and understanding.
I tried compiling the code using:
gcc -O3 main.c -o main -pthread
But the compiler is not acting on global variable counter and is not optimizing it.
I was expecting *thread1_func to execute in a forever loop and the if (counter >= 5) to be never true.
What am I missing here?
GCC Version: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

Your if tests on the value of counter are interspersed with calls to usleep and printf. These are opaque library calls. The compiler cannot see through them and so it has to assume they may have access to the counter external variable, and so it has to reload the counter variable after those calls.
If you move these calls out, the code gets optimized as you expect:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
int counter = 0;
void *thread0_func(void *arg)
{
printf("Thread 0\n");
while(1)
{
}
return NULL;
}
void *thread1_func(void *arg)
{
printf("Thread 1\n");
unsigned i=0;
while(counter == 0)
{
i++;
}
printf("Thread 1: %d, i=%u\n", counter, i);
return NULL;
}
void action_handler(int sig_no)
{
printf("SigINT Generated: %d\n",counter);
counter += 1;
}
int main(int argc, char **argv)
{
pthread_t thread_id[2];
struct sigaction sa;
sa.sa_handler = action_handler;
if(sigaction(SIGINT, &sa, NULL))
perror("Cannot Install Sig handler");
if(pthread_create(&thread_id[0], NULL, thread0_func, NULL))
{
perror("Error Creating Thread 0");
}
if(pthread_create(&thread_id[1], NULL, thread1_func, NULL))
{
perror("Error Creating Thread 0");
}
else
{
}
while(1)
{
if(counter >= 5)
{
printf("Value of Counter is more than five\n");
}
usleep(90000);
}
return (0);
}
Even if you make the counter variable static, the compiler will still not optimize, because although an external library definitely won't see the counter variable, the external call may theoretically have a mutex lock, which would allow another thread to change the variable without a data race. Now neither usleep nor printf are wrappers around a mutex lock, but the compiler doesn't know, nor does it do inter-thread optimization, so it has to be conservative and reload the counter variable after the call and the reload is what prevents the optimization you expect.
Of course, a simple explanation would be that your program is undefined if the signal handler executes, because you should've made counter volatile sig_atomic_t and you should've have synced your inter-thread access to it with either _Atomic or a mutex -- and in an undefined program, anything is possible.

Related

sem_init and pthread_mutex_init

I was writing 2 similar codes for printing odd and even numbers from given number set using mutex lock and semaphore. Both of the codes works fine.
But, while using mutex lock, even if I wont declare the pthread_mutex_init function, still the program executes with no issues. But that's not the case with semaphore. For this case, I have to declare sem_init in main() else the program execution gets stuck in sem_wait() (found after debugging).
So, how in the case of mutex lock, even without declaring init(), the program executes?
For reference, I am attaching the semaphore code.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
sem_t mutex;
pthread_t tid[2];
unsigned int shared_data[] = {23,45,67,44,56,78,91,102};
unsigned int rc;
int len=(sizeof(shared_data)/sizeof(shared_data[0]));
int i=0;
void *even(void *arg) {
rc = sem_wait(&mutex);
int temp = rc;
if(rc)
printf("Semaphore failed\n");
do{
if(shared_data[i] %2 == 0) {
printf("Even: %d\n",shared_data[i]);
i++;
}
else
rc = sem_post(&mutex);
}while(i<len);
}
void *odd(void *arg) {
rc = sem_wait(&mutex);
if(rc)
printf("Semaphore failed\n");
do {
if(shared_data[i] %2 != 0) {
printf("Odd: %d\n",shared_data[i]);
i++;
}
else
rc = sem_post(&mutex);
}while(i<len);
}
int main() {
sem_init(&mutex, 0,1);
pthread_create(&tid[0], 0, &even, 0);
pthread_create(&tid[1], 0, &odd, 0);
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
sem_destroy(&mutex);
return 0;
}
EDIT: Attaching the mutex lock code as well.
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
pthread_t tid[2];
unsigned int shared_data []= {23,45,67,44,56,78,91,102};
pthread_mutex_t mutex;
unsigned int rc;
int len=(sizeof(shared_data)/sizeof(shared_data[0]));
int i=0;
void* PrintEvenNos(void *ptr)
{
rc = pthread_mutex_lock(&mutex);
if(rc)
printf("Mutex lock has failed\n");
do
{
if(shared_data[i]%2 == 0)
{
printf("Even:%d\n",shared_data[i]);
i++;
} else {
rc=pthread_mutex_unlock(&mutex);
}
} while(i<len);
}
void* PrintOddNos(void* ptr1)
{
rc = pthread_mutex_lock(&mutex);
if(rc)
printf("Mutex lock has failed\n");
do
{
if(shared_data[i]%2 != 0)
{
printf("Odd:%d\n",shared_data[i]);
i++;
} else {
rc=pthread_mutex_unlock(&mutex);
}
} while(i<len);
}
void main(void)
{
pthread_create(&tid[0],0,PrintEvenNos,0);
pthread_create(&tid[1],0,PrintOddNos,0);
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
}
So, how in the case of mutex lock, even without declaring init(), the program executes?
This is undefined behavior, so there is no proper result. Per POSIX pthread_mutex_lock():
If mutex does not refer to an initialized mutex object, the behavior of pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() is undefined.
"Appears to work" is one possible result of undefined behavior.
You have sem_init call for sem_t mutex;.
But pthread_mutex_init call is missing for pthread_mutex_t mutex;.
Both of the codes works fine.
No they don't; but first:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Is how you should have initialized your mutex. On your system, this value might be zero, which would be equivalent to what you have. Either way, the problem is your program is broken.
One of your threads (even, odd) acquires a lock. In the case of even, when i is 0,1,2,5 or 6; you unlock it, which would permit odd() to proceed. In the case of odd, when i is 3,4,5 or 7, you unlock it, which would permit even() to proceed. So in your logic, the lock does nothing at all.
Also, semaphores are counters; so when you release it 5 times, you are permitting the next 5 sem_waits to proceed. Simple mutexes are gates, so only the first unlock has any effect, the subsequent 4 are errors. You don't check the error status of the unlock, which is typically the one that uncovers logic errors.
fwiw, on macos, the pthread_mutex_lock()'s both report an error.

No output in stdout when using mutex

anyone have idea how to log data? It sometimes prints something, but mostly nothing. I have no idea, where is a bug... Also tried without mutex, but it still doesn't work.
Thank you very much
Compiled with gcc -o testtest.c -std=c99 -Wall -Wextra -pedantic -pthread
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void logger(const char *msg) {
pthread_mutex_lock(&lock);
printf("%s", msg);
fflush(stdout);
pthread_mutex_unlock(&lock);
}
void *A(void *arg) {
fprintf(stderr, "AAA");
logger("Inside thread A");
return NULL;
}
void *B(void *arg) {
fprintf(stderr, "BBB");
logger("Inside thread A");
return NULL;
}
pthread_t t_id[2];
int main() {
int s1 = pthread_create(&(t_id[0]), NULL, &A, NULL);
int s2 = pthread_create(&(t_id[1]), NULL, &B, NULL);
if (s1 || s2) {
perror("ERROR: Create thread");
exit(2);
}
// EDIT; THIS WAS MISSING
pthread_join(t_id[0], NULL);
pthread_join(t_id[1], NULL);
return 0;
}
To iterate what #πάντα ῥεῖ said.
You need to join your threads, or wait for all threads to finish execution before you exit the application.
Otherwise the application exits before the threads had a chance to print the messages.

Multithreaded semaphore program

I've spent quite a few hours on trying to figure this one out and I'm completly stuck. The program is supposed to start 6 threads. Where some threads start where others end. Right now, I'm trying to get one single thread (thread 0) to execute. The caps lock commenting shows where I have added code and done my mistakes. My main struggle here is dealing with the pointers. Could anyone give me any pointers (ha..ha.. :c )?
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#define SHARED 1
sem_t sem[6];
struct threadargs
{
int id; /* thread number */
int sec; /* how many sec to sleep */
int signal[6]; /* which threads to signal when done */
};
void *tfunc(void *arg)
{
int i;
struct threadargs *targs=arg;
sem_wait(sem); //WAIT FOR OWN SEMAPHORE
printf("Thread %d is running\n", targs->id);
sleep(targs->sec);
printf("Thread %d is completed and may wake others..\n", targs->id);
for(i=0; i<6; i++) //ITERATE OVER signal_ARRAY &
{ //WAKE THREAD NUMBER i IF
if(targs->signal[i] == 1) //signal[i] IS 1
pthread_cond_signal(&sem[i]);
}
}
int main(void)
{
int i, j;
struct threadargs *targs[6];
pthread_t tid[6];
for(i=0; i<6; i++)
{
targs[i] = (struct threadargs*) malloc(sizeof(struct threadargs));
for(j=0; j<6; j++)
{ targs[i]->signal[j]=0; }
}
targs[0]->id=1;
targs[0]->sec=1;
targs[0]->signal[1]=1;
targs[0]->signal[4]=1;
sem[0] = 0; //INITIALIZE THREAD'S SEMAPHORE TO 0 or 1
pthread_create(targs[0], NULL, tfunc, NULL) // START THREAD
for(i=0; i<6; i++)
pthread_join(tid[i], NULL);
return 0;
}
Alright. First things first, I do recommend taking a second look at your coding style. It is of course highly subjective and I won't say yours is bad, but it took me a while to figure it out (if you really want to know, I recommend the Linux coding style for C/C++ code).
Lets get on with your problem. As far as I can see, the main issue seems that you're basically comparing pointers to apples with pointers to banana's (in other words, you're using the wrong pointer type in the wrong place).
To make sure that calls to functions and the like are correct, make sure to look up the API documentation for functions that are new to you (examples: pthread_create, sem_init, sem_wait, sem_post, pthread_cond_signal).
As you can see, pthread_cond_signal doesn't take a sem_t* as argument, and therefore you can't pass one to it and expect it to work. Below you'll find an example program showing how semaphores are used.
First, a new thread is created which will be put in waiting state instantly. As soon as the main tread finished counting from 0 to 150, it will post ('unlock') the semaphore and allowing the second thread to finish its execution.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
static sem_t sem_thread_one;
static pthread_t thread_one_data;
static int x;
static void *tfunc(void *arg)
{
sem_wait(&sem_thread_one);
printf("Thread 1 is running. The value of x is %i\n", x);
return NULL;
}
int main(int argc, char **argv)
{
sem_init(&sem_thread_one, 0 /* don't share between processes */, 0);
if(pthread_create(&thread_one_data, NULL, &tfunc, NULL)) {
fprintf(stderr, "Could not create thread, exiting!\n");
return -EXIT_FAILURE;
}
while(x < 150) {
x++;
}
sem_post(&sem_thread_one);
if(pthread_join(thread_one_data, NULL)) {
fprintf(stderr, "Could not join threads, exiting!\n");
return -EXIT_FAILURE;
}
sem_destroy(&sem_thread_one);
printf("Program ran succesfully!\n");
return -EXIT_SUCCESS;
}
Save in a file sem.c and compile & link using:
gcc -Wall -Os -pthread -o sem_test sem.c
Now a second example, but now using pthread_cond_t. The functionality of the program is somewhat similar, it waits for a counter to reach a certain number.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
static pthread_t thread_one_data, thread_two_data;
static volatile int x, y, idx = 10;
static int count = 1;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
static void *cond_test_wait(void *arg)
{
pthread_mutex_lock(&mutex);
while(count < 10) {
printf("Waiting for `count < 10' to become true\n");
pthread_cond_wait(&condition, &mutex);
}
pthread_mutex_unlock(&mutex);
printf("Test wait thread finished. Value of count: %i\n", count);
return NULL;
}
static void *cond_test_signal(void *arg)
{
while(count < 10) {
pthread_mutex_lock(&mutex);
pthread_cond_signal(&condition);
/* do more intelligent things here */
count++;
pthread_mutex_unlock(&mutex);
}
printf("Test signal thread finished\n");
return NULL;
}
int main(int argc, char **argv)
{
if(pthread_create(&thread_one_data, NULL, &cond_test_wait, NULL)) {
fprintf(stderr, "Could not create thread, exiting!\n");
return -EXIT_FAILURE;
}
if(pthread_create(&thread_two_data, NULL, &cond_test_signal, NULL)) {
fprintf(stderr, "Could not create thread, exiting!\n");
return -EXIT_FAILURE;
}
pthread_join(thread_one_data, NULL);
pthread_join(thread_two_data, NULL);
pthread_cond_destroy(&condition);
pthread_mutex_destroy(&mutex);
printf("Program ran succesfully!\n");
return -EXIT_SUCCESS;
}
Save in a file cond.c and compile & link using:
gcc -o cond -pthread -Os -Wall cond.c
Do note how neat condition work in this example. You can use them to wait until any expression (= condition) becomes true. After the condition becomes true normal execution continue's.
If you need any more help, don't hesitate to ask in the comments. Good luck combining the above examples to fix up your program.

Pthread function starting in C

I'm actually new in processes, threads, semaphores, ipc etc(shortly operating system operations on Linux)... My problem is that I compile my code and It simply gets stuck at so funny points. Processes are executed, but they can't enter their threads' function. After that, program directly ends without doing something. I really can't figure out the problem is here or everything have problem. I don't know.
#define _GNU_SOURCE
#include <sys/types.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
void * function1(void *ptr)
{
printf("Function 1\n"); //!Test prints
printf("Index is %d",*((int *)ptr));
sleep(1);
pthread_exit(NULL);
}
void * function2(void *ptr)
{
printf("Function 2\n"); //!Test prints
printf("Index is %d",*((int *)ptr));
sleep(2);
pthread_exit(NULL);
}
int main(){
//...
int *index;
int i;
pid_t f;
int number_of_process=5;
pthread_t thread1, thread2;
//...
for(i=0; i<number_of_process; i++)
{
f=fork();
if(f==-1)
{
printf("Fork Error!!\n");
exit(1);
}
if(f==0) //To block child processes re-enter
{
*index = i; //I store index number for each process here. I'll need them in the thread functions
break;
}
}
/*******************PARENT PROCESS********************/
if(f!=0){
// wait for all children to exit
while (f = waitpid (-1, NULL, 0)){
if (errno == ECHILD)
break;
}
exit(0);
}
/*******************CHILD PROCESS*********************/
else{
pthread_create(&thread1,NULL,function1,(void *)index);
pthread_create(&thread2,NULL,function2,(void *)index);
}
}
Processes are executed, but they can't enter their threads' function.
After that, program directly ends without doing something.
That's because the main thread (i.e. child process created by fork()) doesn't wait for the threads to complete their execution. So it gives you the impression that the program exits without calling all pthread functions.
Use pthread_join() after creating threads:
...
pthread_create(&thread1,NULL,function1,(void *)index);
pthread_create(&thread2,NULL,function2,(void *)index);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
...
The output may be interleaved due to threads printing without any synchronization.

Using mutex for pthread results in random answer

I have written a simple pthread code which
#include <pthread.h>
#include <stdio.h>
#include <math.h>
#define ITERATIONS 500
// A shared mutex
pthread_mutex_t mutex;
int target;
void* opponent(void *arg)
{
int i;
printf("opp, before for target=%d\n", target);
pthread_mutex_lock(&mutex);
for(i = 0; i < ITERATIONS; ++i)
{
target++;
}
pthread_mutex_unlock(&mutex);
printf("opp, after for target=%d\n", target);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t other;
target = 5;
// Initialize the mutex
if(pthread_mutex_init(&mutex, NULL))
{
printf("Unable to initialize a mutex\n");
return -1;
}
if(pthread_create(&other, NULL, &opponent, NULL))
{
printf("Unable to spawn thread\n");
return -1;
}
int i;
printf("main, before for target=%d\n", target);
pthread_mutex_lock(&mutex);
for(i = 0; i < ITERATIONS; ++i)
{
target--;
}
pthread_mutex_unlock(&mutex);
printf("main, after for target=%d\n", target);
if(pthread_join(other, NULL))
{
printf("Could not join thread\n");
return -1;
}
// Clean up the mutex
pthread_mutex_destroy(&mutex);
printf("Result: %d\n", target);
return 0;
}
Then I compile with this command
gcc -pedantic -Wall -o theaded_program pth.c -lpthread
However, every time I run the program, I get different results!!
$ ./theaded_program
main, before for target=5
main, after for target=-495
opp, before for target=5
opp, after for target=5
Result: 5
$ ./theaded_program
main, before for target=5
opp, before for target=5
opp, after for target=5
main, after for target=-495
Result: 5
The printf() statements are not executed when the mutex is locked and they are accessing target:
printf("opp, before for target=%d\n", target);
pthread_mutex_lock(&mutex);
This means one thread is potentially changing the value of target while another thread is attempting to read it (in the printf()). Move the printf() statements to be executed when the mutex is locked:
pthread_mutex_lock(&mutex);
printf("opp, before for target=%d\n", target);
/* snip */
printf("opp, after for target=%d\n", target);
pthread_mutex_unlock(&mutex);
This will prevent target being read by one thread and modified by another concurrently. However, there is no guarantee which thread will first acquire the mutex.
This result is as expected, your code guarantees that main and opponent are not doing
for(i = 0; i < ITERATIONS; ++i)
{
target--; //or ++ for the opponent
}
at the same time.
The printfs are not in any way protected by the mutex. To avoid this insert the printfs within the mutex lock/unlock

Resources