I recently learned Semaphore and Consumer Producer problem in class and encountered this question:
I used two semaphores to indicate the empty and the full in a buffer plus a mutex.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
pthread_mutex_t mutex;
sem_t empty;
sem_t full;
int fill =0 ;
void *producer(void *param);
void *consumer(void *param);
void* producer(void *param)
{
while(1) {
sem_wait(&empty);
pthread_mutex_lock(&mutex);
fill++;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
}
void *consumer(void *param)
{
while(1){
sem_wait(&full);
pthread_mutex_lock(&mutex);
fill--;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
}
void* dynamic_output(void* ptr){
while(1){
printf("fill = :%d\n",fill);
sleep(1);
}}
int main()
{
pthread_mutex_init(&mutex, NULL);
sem_init(&empty, 0, 5);
sem_init(&full, 0, 0);
pthread_t gid1,oid1;
pthread_t dy;
pthread_create(&dy,NULL,dynamic_output,NULL);
pthread_create(&gid1,NULL,&producer,NULL);
pthread_create(&oid1,NULL,&consumer,NULL);
pthread_join(gid1,NULL);
pthread_join(oid1,NULL);
return 0;
}
here I simply put a variable named 'fill' inside the producer and the consumer. Since I initiated the empty semaphore to 5, I expected 'fill' will be floating between 0 - 5 but when I printed them out I found the weird result:
fill = :0
fill = :19
fill = :446
fill = :112
fill = :156
fill = :-564
fill = :-345
fill = :-744
fill = :-1293
I really don't understand how fill could've become a negative number or number bigger than 5. I thought implementing the semaphores could ensure that the bounded buffer( here I didn't really have a buffer).
Thanks in advance.
Related
Hi I am trying to implement an solution to producer consumer problem with threads and semaphores.
I have the two functions that the threads consumer and producer will call but they aren't executing. I am not sure what I am doing wrong as I am not getting any errors, my program is just not executing the thread functions. I am creating and joining the thread, I am not sure what is causing the issue
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <errno.h>
#include "buffer.h"
struct bufferStruct *item; //calls buffer structure from buffer.h
pthread_mutex_t mutex; //lock for synchronizing execution of threads(producer and consumer)
sem_t empty; //indicates buffer is empty
sem_t full; //indicates buffer is full
int input = 0;
int newitem;
pthread_attr_t attr;
void *producer(void *param)
{
for(int i = 0; i < 5; i++)
{
sem_wait(&empty);
pthread_mutex_lock(&mutex);
newitem = rand();
item->content[item->in] = newitem;
printf("Producer prouced item %d at position %d in buffer\n", newitem, item->in);
item->in = (item->in+1) % MAX_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&full);
sleep(1);
}
}
void *consumer(void * param)
{
for(int i =0; i< 5; i++)
{
sem_wait(&full);
pthread_mutex_lock(&mutex);
newitem = item->content[item->out];
printf("Consumer has consumed item %d at position %d in buffer\n", newitem, item->out);
item->out = (item->out+1) % MAX_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
sleep(1);
}
}
int main()
{
int initval = 1;
int initval2 = 2;
sem_init(&full, 1, 0);
sem_init(&empty, 1, MAX_SIZE);
if(pthread_mutex_init(&mutex,NULL)!=0){
printf("Mutex init failed\n");
return 1;
}
pthread_attr_init(&attr);
pthread_t thread_produce, thread_consume;
printf("Starting threads...\n");
pthread_create(&thread_produce, &attr, producer, (void*)&(initval));
pthread_create(&thread_consume, &attr, consumer, (void*)&(initval2));
pthread_join(thread_produce, NULL);
pthread_join(thread_consume, NULL);
printf("Threads done executing...\n");
pthread_mutex_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
exit(0);
}
You declare
struct bufferStruct *item;
then you use item without ever assigning it to point to anything. Undefined behavior results.
If I fix that (first synthesizing a version struct bufferStruct and choosing a MAX_SIZE) then the program compiles without error and seems to run successfully.
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))
So I'm very new to the whole concept of pthread in C but please hear me out. I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t endCond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t startCond = PTHREAD_COND_INITIALIZER;
void * threadThingy(void * n){
pthread_cond_wait(&startCond, &mutex);
printf("%d: RAND: %d\n", *((int*)n), rand());
//Lock mutex before broadcasting to main thread
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&endCond);
pthread_mutex_unlock(&mutex);
free(n);
fflush(stdout);
return 0;
}
int main(void){
printf("Starting\n");
pthread_t threads[100];
int i = 0;
while(i < 10){
int *arg = malloc(sizeof(int));
*arg = i;
pthread_create(&threads[i], NULL, threadThingy, arg);
i++;
}
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&startCond);
int finished = 0;
while(finished <= 100){
pthread_cond_wait(&endCond, &mutex);
//Lock mutex so no other requests can come in
pthread_mutex_lock(&mutex);
finished++;
int *arg = malloc(sizeof(int));
*arg = 11;
pthread_create(threads[i], NULL, threadThingy, arg);
i++;
pthread_cond_broadcast(&startCond);
pthread_mutex_unlock(&mutex);
}
printf("Stopping\n");
sleep(1000);
}
The whole goal is to run (only) 10 threads simultaneously of the 100. My idea was to start 10 threads, than wait until one is finished and start another one. So I let the program wait until a thread returns, then I start a new one so the thread that just returned gets replaced. What have I missed? Because now I only get this as an output:
Starting
0: RAND: 1804289383
As mentioned by Lavigne958, in function threadThingy() there is deadlock caused by pthread_cond_wait() as it will acquire the lock. Again, you are trying to lock it in next line. This is causing deadlock.
There are a few things need to check:
You need to lock the mutex before calling pthread_cond_wait().
If you solve the above issue, using multiple condition variable with the same mutex may cause further deadlock.
If you are not joining the threads, it will be better to create detached threads using PTHREAD_CREATE_DETACHED attribute.
The problem of N number of threads running simultaneously can be solved with one semaphore OR one condition variable(and one mutex). Example with semaphore is given below.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t mysem;
#define NUM_CONCURRENT_THREADS 4
#define MAX_THREADS 40
void *thread(void *arg)
{
printf("Thread id %ld: started\n", pthread_self());
sleep(5); // Do some work
printf("Thread id %ld: Exiting\n", pthread_self());
sem_post(&mysem);
return NULL;
}
int main()
{
pthread_t t[MAX_THREADS];
pthread_attr_t attr;
int rc, i = 0;
sem_init(&mysem, 0, NUM_CONCURRENT_THREADS);
rc = pthread_attr_init(&attr);
rc = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
printf("\nParent begin\n");
while(i < MAX_THREADS)
{
sem_wait(&mysem);
pthread_create(&t[i], &attr, thread, NULL);
i++;
}
printf("\nParent end.\n");
sem_destroy(&mysem);
return 0;
}
Please check blog Tech Easy for more information on threads.
in the function that your threads run, you start by waiting on a condition but you forgot to take the mutex before. So you first must take the mutex before waiting on the condition.
you have what we call a deadlock.
What happens is:
the first thread wakes up (the pthread_con_wait function acquires the lock for you already)
then you try to acquire the lock again => deadlock because you already own the lock so you kinda deadlock yourself.
With the given shared buffer of size 24,
Here is the below solution, for single producer & consumer using counting semaphore,
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define BUFFERSIZE 24
void *producer(void *);
void *consumer(void *);
sem_t mutex; //Controls buffer access
sem_t fullBuffer; //Prevents underflow
sem_t emptyBuffer; // Prevents overflow
char buf[BUFFERSIZE] = {0}; //Shared resource
int main(int argc, char *argv[])
{
pthread_t thread1, thread2;
sem_init(&mutex, 0, 1);
sem_init(&fullBuffer, 0, 0);
sem_init(&emptyBuffer, 0, BUFFERSIZE);
int ret1, ret2;
ret1 = pthread_create(&thread1, NULL, producer, (void *)0);
ret2 = pthread_create(&thread2, NULL, consumer, (void *)0);
printf("Main function after pthread create\n");
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
sem_destroy(&mutex);
sem_destroy(&fullBuffer);
sem_destroy(&emptyBuffer);
return 0;
}
void *producer(void *index)
{
int * startIndex = index;
int currentProduceIndex = *startIndex;
while(1) {
sem_wait(&emptyBuffer); // Prevents overflow, when value is 0
sem_wait(&mutex); // Controls buffer access
buf[currentProduceIndex] = currentProduceIndex;
sem_post(&mutex);
sem_post(&fullBuffer);
currentProduceIndex = (currentProduceIndex+1) % BUFFERSIZE;
}
}
void *consumer(void *index)
{
int *startIndex = index;
int currentConsumeIndex = *startIndex;
while(1) {
sem_wait(&fullBuffer); // Prevents underflow, when value is 0
sem_wait(&mutex);
printf("Consumed %d: ", buf[currentConsumeIndex]);
sem_post(&mutex);
sem_post(&emptyBuffer);
currentConsumeIndex = (currentConsumeIndex+1) % BUFFERSIZE;
}
}
Above code has single producer and consumer on buf, using 3 semaphores mutex, fullBuffer & emptyBuffer.
To add further, Does 3 semaphore, mutex, fullBuffer & emptyBuffer suffice to introduce multiple producers and consumers to access buf, in the above code?
As seibie pointed out, it is hard to implement using semaphores. I have modified code and used two mutex and two cond variables. You can create multiple producer and consumer threads and it should work fine.
#include <stdio.h>
#include <pthread.h>
#define BUFFERSIZE 24
void *producer(void *);
void *consumer(void *);
pthread_mutex_t consMutex;
pthread_mutex_t prodMutex;
pthread_cond_t consCond;
pthread_cond_t prodCond;
// Shared resource: Using it to store flags.
// If value at index is 0, it means the index is free
// and producer can write data. If it is 1, it means
// that index is filled, consumer can consume it.
// You need use separate array for actual data.
char buf[BUFFERSIZE] = {0};
int main(void)
{
pthread_t thread1, thread2;
pthread_mutex_init(&consMutex, NULL);
pthread_mutex_init(&prodMutex, NULL);
pthread_cond_init(&consCond, NULL);
pthread_cond_init(&prodCond, NULL);
int ret1, ret2;
int prodIndex = 0;
int consIndex = 0;
ret1 = pthread_create(&thread1, NULL, producer, (void *)&prodIndex);
ret2 = pthread_create(&thread2, NULL, consumer, (void *)&consIndex);
printf("Main function after pthread create\n");
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_mutex_destroy(&prodMutex);
pthread_mutex_destroy(&consMutex);
pthread_cond_destroy(&prodCond);
pthread_cond_destroy(&consCond);
return 0;
}
void *producer(void *index)
{
int *currentProduceIndex = index;
while(1) {
pthread_mutex_lock(&prodMutex);
/* Check if current index is free to fill. */
while(1 == buf[*currentProduceIndex])
{
/* If index is not free, wait for consumer to consume. */
pthread_cond_wait(&prodCond, &prodMutex);
}
/* Now the current index is free. Fill it. */
buf[*currentProduceIndex] = 1;
/* Update the producer index. */
*currentProduceIndex = (*currentProduceIndex+1)%BUFFERSIZE;
pthread_mutex_unlock(&prodMutex);
/* Notify consumer that an item has been produced. */
pthread_mutex_lock(&consMutex);
pthread_cond_signal(&consCond);
pthread_mutex_unlock(&consMutex);
}
return NULL;
}
void *consumer(void *index)
{
int *currentConsumeIndex = index;
while(1) {
pthread_mutex_lock(&consMutex);
/* Check if current index is empty. */
while(0 == buf[*currentConsumeIndex])
{
/* If index is empty, wait for producer to produce. */
pthread_cond_wait(&consCond, &consMutex);
}
/* Index is filled, consume it. */
buf[*currentConsumeIndex] = 0;
/* Update the consumer index. */
*currentConsumeIndex = (*currentConsumeIndex+1)%BUFFERSIZE;
pthread_mutex_unlock(&consMutex);
/* Notify producer that an item has been consumed. */
pthread_mutex_lock(&prodMutex);
pthread_cond_signal(&prodCond);
pthread_mutex_unlock(&prodMutex);
}
return NULL;
}
Need help with synchronizing two threads with mutex. Iam new to C and mutexes and Im not sure what to do here. The code has two threads that counts to ten and prints out each number, but is not synch, so it will not print synchronized, it is half synched. Means that i only get trouble in the end, sometimes it prints 8..9..11, 8..9..10..10 and so on.
I cannot make changes to the raw code, if you take away the lines about mutexes, that is the raw code. I can only add lines about mutexes.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex;
int g_ant = 0;
void *writeloop(void *arg) {
while(g_ant < 10) {
pthread_mutex_lock(&mutex);
g_ant++;
usleep(rand()%10);
printf("%d\n", g_ant);
pthread_mutex_unlock(&mutex);
}
exit(0);
}
int main(void)
{
pthread_t tid;
pthread_mutex_init(&mutex, NULL);
pthread_create(&tid, NULL, writeloop, NULL);
writeloop(NULL);
pthread_join(tid, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
With the condition outside your mutex you may not be receiving the correct values. A guaranteed way to ensure the loop operates in-order would be the following change to writeloop:
void writeloop(void *arg) {
while (g_ant < 10) {
pthread_mutex_lock(&mutex);
if (g_ant >= 10) {
pthread_mutex_unlock(&mutex);
break;
}
g_ant++;
usleep(rand()%10);
printf("%d\n", g_ant);
pthread_mutex_unlock(&mutex);
}
}