How to properly sync multithreading with mutex in c? - c

How should i properly sync threads with mutex?
I'm trying a simple "sync" using mutex, something really small, like just printing a string containing the number of the thread. snippet here:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define MAX_RESOURCE 5
#define NO_THREADS 5
int res_available = MAX_RESOURCE;
pthread_mutex_t mtx;
struct count { int no;};
void *
use_res(void *v) {
pthread_mutex_lock(&mtx);
struct count *p = (struct count *) v;
printf("--thread no %d :" p->nr);
return NULL;
}
int main(){
pthread_t thr[NO_THREADS];
pthread_mutex_init(&mtx, NULL);
for(int i=0; i<N0_THREADS; i++){
struct count *c = malloc(sizeof(struct count));
c->nr = i;
pthread_create(thr[i], NULL, use_res, c))
}
for(int i=0; i<NO_THREADS; i++) {
pthread_join(thr[i], NULL);
}
return 0;
}
Fact is, when executed, the sync doesn't actually occur, actually, what it does occur, is still that "race condition", making the program to print something else everytime.
My question is, how do i stop this race condition? I don't know if i'm using correctly this lock and unlock thing.

You need to release mutex when your thread function finish, also add \n at the end of print, because stdout will buffer this text:
void *
use_res(void *v) {
pthread_mutex_lock(&mtx);
struct count *p = (struct count *) v;
printf("--thread no %d :\n" p->no);
pthread_mutex_unlock(&mtx);
return NULL;
}

Related

Problem with running a function in 2 threads in C

I have written a program with a function that prints a character received as an argument continuously, and made 2 threads running that function. The program runs as intended and keeps printing 2 characters interlaced indefinitely. Here is the code:
#include <pthread.h>
#include <stdio.h>
void* print_char(void* th_param) {
char* ch = (char*)th_param;
while(1)
printf("%c", *ch);
return NULL;
}
int main() {
char* c1 = "a";
char* c2 = "b";
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, (void*)c1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, (void*)c2);
return 0;
}
Now I have to modify this program so the print function takes a number argument as well, and prints the character that number of times. What I try is this:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct Params {
char* ch;
int num;
};
void* print_char(void* th_param) {
int i;
struct Params* par = (struct Params*)th_param;
for(i=0; i<par->num; i++) {
printf("%s", par->ch);
}
return NULL;
}
int main() {
struct Params* p1 = (struct Params*)malloc(sizeof(struct Params));
p1->ch = "a"; p1->num = 5;
struct Params* p2 = (struct Params*)malloc(sizeof(struct Params));
p2->ch = "b"; p2->num = 10;
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, (void*)p1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, (void*)p2);
while(1) {}
return 0;
}
But to no avail. Doesn't print a single character, the cursor just stands there blinking doing nothing. I have tried tampering with the code for hours and nothing has worked.
Note that there's not a problem with the struct, because the program works if I remove the for loop and put while(1) instead, and prints the character given to par->ch infinite times again.
The problem is buffered I/O.
Your main()-function loops infinitely, so the process doesn't terminate properly (only by being killed via an external signal), so the stdout-buffer is never flushed by regular process termination.
Since stdout is line-buffered by default, and your printf()s don't contain any newlines, and the amount of characters you try to print is smaller than the I/O-buffer, your program never writes out the buffer, so nothing is printed.
One approach would be to add fflush(stdout); after the printf()s in your thread function, or include a '\n' in the output.
Another (more sane) approach would be to have main() actually wait for the threads to finish, and gracefully terminate when they are done:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct Params {
char* ch;
int num;
};
void* print_char(void* th_param) {
int i;
struct Params* par = (struct Params*)th_param;
for(i=0; i<par->num; i++) {
printf("%s", par->ch);
//fflush(stdout);
}
return NULL;
}
int main() {
struct Params* p1 = (struct Params*)malloc(sizeof(struct Params));
p1->ch = "a"; p1->num = 5;
struct Params* p2 = (struct Params*)malloc(sizeof(struct Params));
p2->ch = "b"; p2->num = 10;
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, (void*)p1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, (void*)p2);
//while(1) {}
pthread_join(th_id, NULL);
pthread_join(th_id2, NULL);
free(p1); //make LeakSanitizer happy, don't leak memory
free(p2);
puts(""); //one newline for command-line beautification
fflush(stdout); //redundant after the puts(""), unless stdout is redirected to a non-interactive stream
return 0;
}
Thanks everyone, using fflush did the job.
To answer the person who asked what platform I ran this on, I was running this on Linux terminal. This was the homework for my OS lab class and pthread_create is all they have taught us so far, pthread_join and more thread management stuff come in later sessions.
Because of your while loop, stdout never get's flushed
Try this :
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct Params {
char* ch;
int num;
};
void* print_char(void* th_param) {
int i;
struct Params* par = (struct Params*)th_param;
for(i=0; i<par->num; i++) {
printf("%s", par->ch);
}
return NULL;
}
int main() {
struct Params* p1 = malloc(sizeof(struct Params));
p1->ch = "a"; p1->num = 5;
struct Params* p2 = malloc(sizeof(struct Params));
p2->ch = "b"; p2->num = 10;
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, p1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, p2);
fflush(stdout);
while(1) {;}
return 0;
}

Bounded buffer sharing with Pthread and mutex locks busy waiting

I am trying to create a producer consumer queue, using mutex locks, creating busy waiting between threads. My Main file takes X amount of integer arguments, pushes them onto a BOUNDED BUFFER of size 50. I am using a while loop to do this since you do not know the amount before hand. I am not sure when and where to create my producer thread.
NOTE: Main is a "producer" in the sense it fills the buffer, but my actual producer function is going to pass onto my consumer function later in my code, so disregard the names. Main is going to "Produce" numbers by pushing and producer is going to pop those numbers for later use. My question is where and when do I make my Pthread_create in my code for producer and am I using the Mutex locks correctly to have synchronization between the two threads?
#include <pthread.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#define BUFFER_SIZE (50)
typedef struct {
int buffer[BUFFER_SIZE];
int count;
int top;
int next;
pthread_mutex_t count_lock;
} prodcons;
void pc_init(prodcons *pc);
int pc_pop(prodcons *pc);
void pc_push(prodcons *pc, int val);
void factor2pc(prodcons *pc, int number);
void *producer(void *data);
void *consumer(void *data);
int main(int argc, char *argv[])
{
int index = 1;
int num;
prodcons pc_nums;
//pthread_t tid[argc - 1];
pthread_t tid;
pthread_attr_t attr;
if (argc < 2) {
fprintf(stderr, "usage: No arguments\n");
return -1;
}
if (atoi(argv[1]) <= 0)
{
fprintf(stderr, "%d not > 0 or you must provide a positive integer.\n", atoi(argv[1]));
return -1;
}
pthread_attr_init(&attr);
pc_init(&pc_nums);
//DO I PUT THIS HERE or WHILE LOOP?
pthread_create(&tid, &attr, *producer, &pc_nums);
while (index < argc)
{
num = atoi(argv[index]);
pc_push(&pc_nums, num);
index++;
}
}
void *producer(void *data)
{
prodcons *dataStruct = data;
while (dataStruct->count < BUFFER_SIZE)
{
number = pc_pop(data);
//This print is just here to make sure I am correctly "poping" from buffer
printf("%d\n", number);
}
}
void pc_init(prodcons *pc)
{
pc->count = 0;
pc->top = 0;
pc->next = 0;
if (pthread_mutex_init(&pc->count_lock, NULL) != 0)
{
printf("\n mutex init has failed\n");
}
}
int pc_pop(prodcons *pc)
{
int val;
pthread_mutex_lock(&pc->count_lock);
if (pc->count > pc->top)
{
val = pc->buffer[pc->count];
printf("%d\n", val);
pc->buffer[pc->count] = 0;
pc->count--;
}
pthread_mutex_unlock(&pc->count_lock);
return val;
}
void pc_push(prodcons *pc, int val)
{
pthread_mutex_lock(&pc->count_lock);
if (pc->count < BUFFER_SIZE)
{
pc->buffer[pc->count] = val;
pc->count++;
}
pthread_mutex_unlock(&pc->count_lock);
}
My question is where and when do I make my Pthread_create in my code for producer and am I using the Mutex locks correctly to have synchronization between the two threads?
As long as all is properly initialized and synchronized, you can put the pthread_create() call wherever you want, including where it's placed in the given program. But at least two things are wrong:
pc_pop() behaves undefined (by return of an uninitialized value) if there is no number in the buffer to pop.
Since dataStruct->count is accessed by producer() without locking, the declaration should be _Atomic(int) count;.

Understanding pthread

I'm currently confused as to why the following code won't print the following:
My value is 0
My value is 1
My value is 2
Every time I run this I either get 1-2 printed lines or nothing and the program just sits their until I ctrl-c. I feel like it might have something to do with me using the same condition variable and mutex with 3 different threads, would this be correct? Any explanations are greatly appreciated.
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
struct id_holder
{
int id;
};
pthread_mutex_t intersectionMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t directionCondition = PTHREAD_COND_INITIALIZER;
struct id_holder * holder;
void * logic(void* val)
{
struct id_holder * id_struct = (struct id_holder *) val;
pthread_cond_wait(&directionCondition, &intersectionMutex);
printf("My value is %d\n", id_struct->id);
free(id_struct);
return NULL;
}
int main(void)
{
pthread_t threads[3];
for(int i = 0; i <3; i++)
{
holder = (struct id_holder *) malloc(sizeof(struct id_holder));
holder->id = i;
pthread_create(&threads[i], NULL, logic, holder);
}
for(int i = 0; i < 3; i++)
{
sleep(1);
pthread_cond_signal(&directionCondition);
}
for(int i = 0; i < 3; i++)
{
pthread_join(threads[i], NULL);
}
return 0;
}
When condition is waited for or signalled, it must be done under the lock, otherwise the behavior is unpredictable as it could into race condition. Therefore your code should look like:
pthread_mutex_lock(&intersectionMutex);
pthread_cond_wait(&directionCondition, &intersectionMutex);
pthread_mutex_unlock(&intersectionMutex);
And the same for main (you can move the lock outside the loop if you wish):
for(int i = 0; i < 3; i++) {
sleep(1);
pthread_mutex_lock(&intersectionMutex);
pthread_cond_signal(&directionCondition);
pthread_mutex_unlock(&intersectionMutex);
}
Still the code is not 100% safe as the main thread can signal the condition before the child thread invokes the wait. Although it's highly improbable here due to sleep() in the main function, generally there should be a variable that identifies whether the wait is actually needed or not. In other words, conditions are not queue but can be used to create queue.

How can I have a shared counter in multithreading using structs?

I'm pretty new with multithreading and I was trying to increment a shared counter whithout using global variables, my goal is try to maximize the concurrency among the different threads and increment the variable until a number I give in arguments... Sorry if is a lame question, but I would like a help here, when I compile my code and run it i get a segmentation fault... I think the error is in the variable count that I create and the shared counter!
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex;
typedef struct {
long *cnt; /* pointer to shared counter */
long n; /* no of times to increment */
int nr;
pthread_t id; /* application-specific thread-id */
} targ_t;
void *sfun(void *arg) {
targ_t *est = (targ_t *) arg;
here:
pthread_mutex_lock(&mutex);
(*(est->cnt))++;
pthread_mutex_unlock(&mutex);
if(*(est->cnt)<est->n)
goto here;
return NULL;
}
int main(int argc, char *argv[]){
targ_t real[3];
int c=0;
long count=0;
real[0].cnt=&count;
pthread_mutex_init(&mutex, NULL);
for(c=0;c<3;c++){
real[c].n=atoi(argv[1]);
real[c].nr=c+1;
pthread_create(&real[c].id,NULL,&sfun,&real[c]);
}
for(c=0;c<3;c++){
pthread_join(real[c].id,NULL);
}
pthread_mutex_destroy(&mutex);
printf("OVERALL %lu\n", count);
return 0;
}
TY in advance.
There are a number of problems identified in the comments:
Writing out loops with a label here: and a goto here; is not a particularly good idea. There are occasions (some, but not many, occasions) when it is appropriate to use goto — this is not one of those rare occasions.
You don't actually validate that your code was given an argv[1] to convert; could it be that you forgot to pass that argument?
However, your primary problem is that you initialize real[0].cnt but you do not initialize real[1].cnt or real[2].cnt, so those threads are accessing who knows what memory — it might be that they're using null pointers, or they might be pointers to anywhere in memory, allocated or not, aligned or not, writable or not.
You're also missing <stdlib.h>
You're testing *(est->cnt) outside the scope of mutual exclusion.
This code fixes those and some other issues:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct
{
long *cnt; /* pointer to shared counter */
long n; /* no of times to increment */
int nr;
pthread_t id; /* application-specific thread-id */
} targ_t;
static void *sfun(void *arg)
{
targ_t *est = (targ_t *)arg;
while (1)
{
pthread_mutex_lock(&mutex);
long cval = *est->cnt;
if (cval < est->n)
++*est->cnt;
pthread_mutex_unlock(&mutex);
if (cval >= est->n)
break;
}
return NULL;
}
int main(int argc, char *argv[])
{
targ_t real[3];
long count = 0;
if (argc != 2)
{
fprintf(stderr, "Usage: %s count\n", argv[0]);
return(EXIT_FAILURE);
}
for (int c = 0; c < 3; c++)
{
real[c].cnt = &count;
real[c].n = atoi(argv[1]);
real[c].nr = c + 1;
if (pthread_create(&real[c].id, NULL, &sfun, &real[c]) != 0)
break;
}
for (int c = 0; c < 3; c++)
pthread_join(real[c].id, NULL);
pthread_mutex_destroy(&mutex);
printf("OVERALL %lu\n", count);
return 0;
}
When run (for example, the program is pth59):
$ pth59 100
OVERALL 100
$
Before moving the test (now on cval) so that the read of *est->cnt was done inside the scope of the mutex, I got an output OVERALL 102 from the same command line. It is important to access shared variables with proper mutual exclusion, even if it is read-only access.

Linux Pthread argument

This is my code. It's very simple.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *func(void *arg)
{
printf("ID=%d\n", *(int*)arg);
pthread_exit(NULL);
}
int main()
{
pthread_t pt[4];
int i;
for (i = 0; i < 4; i++)
{
int temp = i;
pthread_create(&pt[i], NULL, func, (void*)&temp);
}
sleep(1);
return 0;
}
I compiled it:
gcc p_test.c -lpthread
I ran it. It printed 2 2 3 3. I ran it again. It printed 2 3 3 2.
My problem is:
Why was 2 or 3 printed twice?
Why didn't it print 1 3 2 0 or any other results?
The major problem here is that you're taking the address of the local variable temp, and then using that pointer outside the scope of the variable - as soon as you exit one iteration of the loop, your pointer to temp becomes invalid and you must not dereference it.
You're passing a pointer to a temporary variable into the thread creation function and this temporary goes out of scope at the end of the loop block. It would seem to me that the temporary address is being reused by the compiler and so that when the threads are executing, they see the same address location.
If you do:
int *temp = malloc(sizeof(int));
*temp = i;
pthread_create(&pt[i], NULL, func, (void*)temp);
instead, you should see the results you expect.
In this case, the thread function needs to free the int after it is printed it to avoid a memory leak.
Also, it's better practice to pthread_join() the threads that you're waiting for rather than just sleep()ing.
because it prints temp, all threads shares the memory(why temp is "shared" is explained by TheJuice), so all threads "share" temp . Use a mutex or make temp a private variable.
Private Variables in Threads
Or you can use phtread_join like this:
int main()
{
pthread_t pt[4];
int i;
for (i =0 ; i < 4; i++)
{
pthread_create(&pt[i], NULL, func, (void*)&i);
pthread_join(pt[i],NULL);
}
//sleep(1);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *func(void* arg)
{
printf("ID=%d\n", (int)arg);
pthread_exit(NULL);
return 0;
}
int main()
{
pthread_t pt[4];
int i;
for (i =0 ; i < 4; i++)
{
pthread_create(&pt[i], NULL, func, (void*)i);
pthread_join(pt[i],NULL);
}
return 0;
}

Resources