i'm working on the producer consumer problem in C where i get the producers and consumers as input and i have to produce/consume 8192 elements.
My code is :
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex;
sem_t empty;
sem_t full;
int prod=0;
int cons=0;
int buffer[8];
int in=0;
int out=0;
void producer(void* x)
{
int z=1;
while(z)
{
int item=rand();
sem_wait(&empty);
pthread_mutex_lock(&mutex);
if (prod!=8192){
buffer[in]=item;
prod+=1;
printf("Prod %d:item ins %d at %d\n",*((int *)x),buffer[in],in);
in=(in+1)%8;
}
if(prod==8192){z=0;}
pthread_mutex_unlock(&mutex);
sem_post(&full);
for (int i=0; i<10000; i++);
}
}
void consumer(void*x)
{
int z=1;
while(z)
{
sem_wait(&full);
pthread_mutex_lock(&mutex);
if (cons!=8192){
int item = buffer[out];
cons+=1;
printf("Cons %d:item rm %d at %d\n",*((int *)x),item,out);
out =(out+1)%8;
}
if(cons==8192){z=0;}
pthread_mutex_unlock(&mutex);
sem_post(&empty);
for (int i=0; i<10000; i++);
}
}
int main(int argc, char const *argv[])
{
int nbProd=atoi(argv[1]);
int nbCons=atoi(argv[2]);
pthread_t produc[nbProd],conso[nbCons];
pthread_mutex_init(&mutex,NULL);
sem_init(&empty,0,8);
sem_init(&full,0,0);
int idP[nbProd];
for (int i=0; i< nbProd;i++){
idP[i]=i;
}
int idC[nbCons];
for (int i=0; i< nbCons;i++){
idC[i]=i;
}
for(int i=0;i<nbProd;i++){
pthread_create(&produc[i],NULL,(void *)producer,(void*)&idP[i]);
}
for(int i=0;i<nbCons;i++){
pthread_create(&conso[i],NULL,(void *)consumer,(void*)&idC[i]);
}
for(int i=0;i<nbProd;i++){
pthread_join(produc[i],NULL);
}
for(int i=0;i<nbCons;i++){
pthread_join(conso[i],NULL);
}
pthread_mutex_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
printf("prod:%d,-cons:%d",prod,cons);
return 0;
}
I tried the different input as :
./main 3 3
./main 1 3
Most case of equals producers/consumers everything is fine
Case of inequals producers/consumers there is a deadlock situation.
I tried to find where does it come from with helgrind.
The output was talking about "Possible data race Locks held: none"
But i couldnt find the answer to this.
I expect my program to execute the producers/consumers problem for equals and inequals producers/consumers.
Case of inequals producers/consumers there is a deadlock situation.
Running the program under GDB with ./a.out 1 3 arguments shows that there are 3 threads: the main thread blocked in pthread_join and two consumer threads blocked on sem_wait(&full).
With that info the problem becomes immediately obvious: you start full at 0, you increment it nbProd times, and you decrement it nbCons times.
When nbCons > nbProd, the decrements can not proceed and wait forever.
To fix this, you need to increment full nbCons - nbProd times to account for imbalance.
Related
First of all I am still new to posix programming and still understanding basic concepts. It is still not very clear for me how do pthread_mutex_lock
pthread_mutex_unlock do work.
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#inlcude <stdio.h>
pthread_mutex_t_mtx;
void* routine(void* i){
int j;
for(j = 0; j < 1000000; ++j){
pthread_mutex_lock(&mtx);
printf("Inside thread %d\n", i);
pthread_mutex_unlock(&mtx);
}
return NULL;
}
int main()
{
pthread_t th[3];
int i;
pthread_mutex_init(&mtx, NULL);
for(i = 1; i <= 2; ++i)
{
if(pthread_create(th + i, NULL, routine, i){
perror(NULL); return 1;
}
}
for(i = 1; i <=2; ++i)
pthread_join(th[i], NULL);
return 0;
}
What should be the correct output of the above program ? I think that because of the lock and unlock of the mutex there would be 2000000 iterations, but it is not very clear for me the order that they are done in. Does the first thread execute the first 1000000 steps of the for? Does it even execute the first one of the 20000000 ? Or does this happen by a more chaotic order?
Assuming that the mutex is a global one, you will get 2000000 messages, with 1000000 from each thread. The order of those is random, however they will not interfere each other as each print is protected by the mutex
EDIT: I just noticed, that you are joining before creating the next thread. Therfore first there will be all messages of the first, then of the second thread. In this case the mutex has no effect at all. The reason for the ordering is simply that you will not have more then one worker-thread running at the same time.
This is my current code for the Producer-Consumer problem. I compiled it and ran it but nothing is printed. The command line takes in 3 arguments: Sleep time, producer threads, consumer threads. I've tried setting the values as 5, 1, 1 respectively, the sleep timer works but I'm unsure about the rest.
Code for buffer.h:
typedef int buffer_item;
#define BUFFER_SIZE 5
Code for buffer.c:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include "buffer.h"
buffer_item buffer[BUFFER_SIZE];
void *producer(void *param);
void *consumer(void *param);
pthread_mutex_t mutex;
sem_t empty;
sem_t full;
int insert_item(buffer_item item)
{
do
{
wait(empty);
wait(mutex);
signal(mutex);
signal(full);
}while(1);
return 0;
}
int remove_item(buffer_item *item)
{
do
{
wait(full);
wait(mutex);
signal(mutex);
signal(empty);
}while(1);
return 0;
}
int main(int argc, char *argv[])
{
int sleepTime;
int producerThreads;
int consumerThreads;
int counter_1;
int counter_2;
if(argc != 4)
{
return -1;
}
sleepTime = atoi(argv[1]);
producerThreads = atoi(argv[2]);
consumerThreads = atoi(argv[3]);
srand((unsigned)time(NULL));
for(counter_1 = 0; counter_1 < producerThreads; counter_1++)
{
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tid, &attr, producer, NULL);
}
for(counter_2 = 0; counter_2 < consumerThreads; counter_2++)
{
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tid, &attr, consumer, NULL);
}
sleep(sleepTime);
return 0;
}
void *producer(void *param)
{
buffer_item item;
int randomTime;
int counter_1 = 0;
while(1)
{
randomTime = rand() % 1000 + 1;
sleep(randomTime);
item = rand();
if(insert_item(item))
{
fprintf(stderr, "Error.");
}
else
{
printf("Producer ID: %lu, Produced Item: %d\n", pthread_self(), item);
printf("The buffer now contains %d items\n", counter_1);
++counter_1;
}
}
}
void *consumer(void *param)
{
buffer_item item;
int randomTime;
int counter_2 = 0;
while(1)
{
randomTime = rand() % 1000 + 1;
sleep(randomTime);
if(insert_item(item))
{
fprintf(stderr, "Error.");
}
else
{
printf("Consumer ID: %lu, Consumed Item: %d\n", pthread_self(), item);
printf("The buffer now contains %d items\n", counter_2);
++counter_2;
}
}
}
So far I've tried declaring the tid separately, skipping sleep and join the threads, but it still doesn't print.
Your code can't possibly run, indeed it doesn't even compile.
Here's a list of issues that need to be addressed:
wait should be sem_wait
signal should be sem_post for semaphores
int sem_wait(sem_t *sem); and int sem_post(sem_t *sem); take the pointer to a semaphore
sem_wait(mutex) and sem_post(mutex) give something like "incompatible type for argument 1 of sem_wait", I guess you want to acquire and release the lock on the mutex like pthread_mutex_lock(&mutex) and pthread_mutex_unlock(&mutex)
in the consumer if(insert_item(item)): item is used uninitialized
still in the consumer you use insert_item instead of remove_item
Coming to the main question "I compiled it and ran it but nothing is printed", it doesn't print anything because producer and consumer call, respectively, insert_item and remove_item and are trapped inside infinite loops (e.g. while(1))
I have problem with semaphore in C. I have a parent process and a child process. Both can create 3 threads and I must display the beginning and the end of threads and I must impose the next condition: the thread with id 1 from parent process must display its beginning after the thread with id 2 from child process display its end. I use a semaphore, but when I do wait, the thread with id 1 from parent process it doesn't remain stuck at semaphore and continue to display the beginning. I can't use function usleep() or sleep().
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <semaphore.h>
sem_t* s=NULL;
void* function1(void* arg)
{
int* nrth=(int*) arg;
sem_t * s=NULL;
s=sem_open("mysemaphore",O_EXCL);
if(s==NULL)
perror("Error");
if(*nrth==1)
sem_wait(s);
printf("Begin P1, thread %d\n",*nrth);
printf("End P1, thread %d\n",*nrth);
sem_close(s);
return 0;
}
void* function2(void* arg)
{
int* nrth=(int*) arg;
sem_t * s=NULL;
s=sem_open("mysemaphore",O_EXCL);
if(s==NULL)
perror("Error");
printf("Begin P2, thread %d\n",*nrth);
printf("End P2, thread %d\n",*nrth);
if(*nrth==2)
sem_post(s);
sem_close(s);
return 0;
}
int main()
{
sem_unlink("mysemaphore");
s=sem_open("mysemaphore",O_CREAT,0644,1);
if(s==NULL)
perror("ERROR!");
pthread_t threads[4];
int index[4];
pthread_t threads2[4];
int index2[4];
if(fork()==0)
{
printf("Begin: process 2 \n");
for(int i=1; i<=3; i++)
{
index2[i]=i;
pthread_create(&threads2[i],NULL,function2,&index2[i]);
}
for(int i=1; i<=3; i++)
{
pthread_join(threads2[i],NULL);
}
printf("End: process 2 \n");
}
else
{
printf("Begin: process 1\n");
for(int i=1; i<=3; i++)
{
index[i]=i;
pthread_create(&threads[i],NULL,function1,&index[i]);
}
for(int i=1; i<=3; i++)
{
pthread_join(threads[i],NULL);
}
printf("End: process 2 \n");
wait(NULL);
}
return 0;
}
You are destroying your semaphore in both function1() and function2() when you call sem_destroy(), after which the behavior of that semaphore is undefined. That may be your biggest problem.
You should be using sem_close() instead after you are finished using the semaphore that you obtained from sem_open().
I'm trying to synchronize multiple (7) threads. I thought I understood how they work until I was trying it on my code and my threads were still printing out of order. Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
void *text(void *arg);
long code[] = {4,6,3,1,5,0,2}; //Order in which to start threads
int num = 0;
pthread_mutex_t lock; //Mutex variable
int main()
{
int i;
pthread_t tid[7];
//Check if mutex worked
if (pthread_mutex_init(&lock, NULL) != 0){
printf("Mutex init failed\n");
return 1;
}
//Initialize random number generator
time_t seconds;
time(&seconds);
srand((unsigned int) seconds);
//Create our threads
for (i=0; i<7; i++)
pthread_create(&tid[i], NULL, text, (void*)code[i]);
//Wait for threads to finish
for (i=0; i<7; i++){
if(pthread_join(tid[i], NULL)){
printf("A thread failed to join\n");
}
}
//Destroy mutex
pthread_mutex_destroy(&lock);
//Exit main
return 0;
}
void *text (void *arg)
{
//pthread_mutex_lock(&lock); //lock
long n = (long) arg;
int rand_sec = rand() % (3 - 1 + 1) + 1; //Random num seconds to sleep
while (num != n) {} //Busy wait used to wait for our turn
num++; //Let next thread go
sleep(rand_sec); //Sleep for random amount of time
pthread_mutex_lock(&lock); //lock
printf("This is thread %d.\n", n);
pthread_mutex_unlock(&lock); //unlock
//Exit thread
pthread_exit(0);
}
So here I am trying to make threads 0-6 print IN ORDER but right now they are still scrambled. The commented out mutex lock is where I originally had it, but then moved it down to the line above the print statement but I'm having similar results. I am not sure where the error in my mutex's are, could someone give a hint or point me in the right direction? I really appreciate it. Thanks in advance!
You cannot make threads to run in order with only a mutex because they go in execution in an unpredictable order.
In my approach I use a condition variable and a shared integer variable to create a queueing system. Each thread takes a number and when the current_n number is equal to the one of the actual thread, it enters the critical section and prints its number.
#include <pthread.h>
#include <stdio.h>
#define N_THREAD 7
int current_n = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t number = PTHREAD_COND_INITIALIZER;
void *text (void *arg) {
int i = (int)arg;
pthread_mutex_lock(&mutex);
while ( i > current_n ) {
pthread_cond_wait(&number, &mutex);
}
//i = current_n at this point
/*I use stderr because is not buffered and the output will be printed immediately.
Alternatively you can use printf and then fflush(stdout).
*/
fprintf(stderr, "I'm thread n=%d\n", i);
current_n ++;
pthread_cond_broadcast(&number);
pthread_mutex_unlock(&mutex);
return (void*)0;
}
int main() {
pthread_t tid[N_THREAD];
int i = 0;
for(i = 0; i < N_THREAD; i++) {
pthread_create(&tid[i], NULL, text, (void *)i);
}
for(i = 0; i < N_THREAD; i++) {
if(pthread_join(tid[i], NULL)) {
fprintf(stderr, "A thread failed to join\n");
}
}
return 0;
}
The output is:
I'm thread n=0
I'm thread n=1
I'm thread n=2
I'm thread n=3
I'm thread n=4
I'm thread n=5
I'm thread n=6
Compile with
gcc -Wall -Wextra -O2 test.c -o test -lpthread
Don't worry about the warnings.
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.