Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to synchronize threads?

I used threads in this code. but when I execute this code in shell, some threads didn't print this line.

printf("\ti'm %dth thread:)", j);  
printf("\t%c  %d  %d  %d \n", arr[j].op, arr[j].byte, seq, no_file);

In addition, even some threads print this line twice. what happened to this process? And how to reorganize this code in order to threads print the line exactly once?

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

typedef struct {char op; int byte; int seq; int no_file; } ARRAY; 

ARRAY *arr;

void *thread_operation(void *arg){
    int j =*((int*)arg);
    seq = arr[j].seq;
    int no_file = arr[j].no_file;
    printf("\ti'm %dth thread:)", j);
    printf("\t%c  %d  %d  %d \n", arr[j].op, arr[j].byte, seq, no_file);
}

int main()
{
    int err, j, i = 10;
    long int tid;
    arr = (ARRAY*)malloc(sizeof(ARRAY) * i);
    srand(time(NULL));
    for (i = 0; i <= 10; i++){
        arr[i].op = 'r';
        arr[i].byte = (rand() % 10);
        arr[i].seq = i;
        arr[i].no_file = i + 10;
}

    for(j = 0; j < 10; j++){
        printf("creating %dth thread.....", j);
        err = pthread_create(&tid, NULL, thread_operation, &j);
        if(err != 0)
        printf("%s\n", strerror(err));
        printf("%dth done\n", j);
    }

    return 0;
}

This is result from my pc

creating 0th thread.....0th done
creating 1th thread.....    i'm 0th thread:)    r  9  0  10
1th done
creating 2th thread.....    i'm 2th thread:)    r  3  2  12
    i'm 2th thread:)    r  3  2  12
2th done
creating 3th thread.....    i'm 3th thread:)    r  6  3  13
3th done
creating 4th thread.....    i'm 4th thread:)    r  9  4  14
4th done
creating 5th thread.....    i'm 5th thread:)    r  3  5  15
5th done
creating 6th thread.....    i'm 6th thread:)    r  2  6  16
6th done
creating 7th thread.....    i'm 7th thread:)    r  2  7  17
7th done
creating 8th thread.....8th done
creating 9th thread.....    i'm 8th thread:)    r  6  8  18
9th done
    i'm 9th thread:)    r  8  9  19  
    i'm 9th thread:)    r  8  9  19
like image 292
manut Avatar asked Jan 19 '23 19:01

manut


2 Answers

You need to use mutexes ton avoid race conditions, and you also need to use pthread_join to synchronize all your threads before the process dies.

Mutexes allow you to stop some threads while one of them is executing an action using a shared ressource (see man pthread_mutex_lock, pthread_mutex_init)

pthread_join is essential in your code, because it forces your main thread to wait for the other threads you created, if you don't use it, you're not sure all threads will be finished when the main thread returns from the main.

like image 95
Intrepidd Avatar answered Jan 29 '23 11:01

Intrepidd


The reason why some are printing out twice (such as thread number 9) is because you are passing a pointer to your loop variable as the input to the thread_operation.

for(j = 0; j < 10; j++){
    err = pthread_create(&tid, NULL, thread_operation, &j);<---here

that &j is eventually dereferenced by thread_operation:

void *thread_operation(void *arg){
    int j =*((int*)arg);<---here

but at this point the loop could have advanced and the value of j (in the thread operation) will be whatever j happens to be in the loop right now. The way to fix this is to not pass a pointer but the value of j to the thread constructor. Change your pthread_create to pass the value:

pthread_create(&tid, NULL, thread_operation, (void*) j);

and in your thread cast the value out of the thread argument:

int j =(int)arg;

Now technically this relies on the fact that int and void* are the same size when in general they are not. But this will work as long as you aren't using giant int values.

for all the other problems @Intrepidd is right about using pthread_join to make sure that the process doesn't exit before all your threads complete.

like image 43
luke Avatar answered Jan 29 '23 12:01

luke