I tried to simulate the producer consumer problem using bounder buffer in C and threads.
Mutex and semaphores are also used.
The expected output is to display the state of buffer every time an item is produced or consumed.
Buffer size is fixed as 10. Initially buffer items are all -1. When a producer produces an item into it, the item replaces -1.
Item in 0th index is 0 ,1st index is 1 and so on.....which doesn't matter.
The program asks the number of producers and consumer we want to create.
The production is working fine....but not consumption.
Segmentation fault arises in Thread 1.I am not sure what Thread 1 is.
I tried to debug using GDB many times....without no hope.
// Producer consumer.
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#define TRUE 1
int buff_size=10,i;
int buffer[25];
pthread_mutex_t mutex;
sem_t full, empty;
int counter = 0;
int consume_count=0; //No of Consumers created
int produce_count=0; //No of Producers created
void initializeData()
{
sem_init(&full, 0, 0);
sem_init(&empty, 0, buff_size);
pthread_mutex_init(&mutex, NULL);
}
int insert_item(int counter)
{
if (counter < buff_size) {
buffer[counter] = counter;
counter++;
//produce_count++;
return 0;
}
else {
printf("\n[BUFFER FULL!]");
return -1;
}
}
int remove_item()
{
printf("\n[GOING TO REMOVE AN ITEM]\n");
if (buffer[counter-1] != -1) {
buffer[counter-1] = -1;
counter--;
//consume_count++; // Commented out...
return 0;
}
else {
printf("\n[EMPTY]\n");
return -1;
}
}
void *producer(void *arg)
{
int RET = 0;
while( TRUE ) {
sem_wait(&empty);
pthread_mutex_lock(&mutex);
RET = insert_item(counter);
if (RET){
printf("\nProducer Sleeping...zzZZ\n");
sleep(2);
}
pthread_mutex_unlock(&mutex);
sem_post(&full);
if(!RET)
printf("\n[ INSERTED ]\n" );
printf("\n");
for(i=0; i < buff_size ;i++)
printf("[%d] ",buffer[i]);
printf("\n");
sleep(3);
} // end of while...
}
void *consumer(void *arg)
{
int RET = 0;
while( TRUE ) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
RET = remove_item(buffer);
if (RET){
printf("\nConsumer Sleeping\n");
sleep(3);
}
pthread_mutex_unlock(&mutex);
sem_post(&empty);
if(!RET) {
printf("\nConsumed\n");
printf("\n");
}
for(i=0 ; i < buff_size ; i++)
printf("%4d",buffer[i]);
printf("\n");
sleep(2);
} //end of while...
}
void main()
{
int produce, consume;
pthread_t *prod;//thread ID
pthread_t *cons;//thread ID
printf("\nEnter the no of producers: ");
scanf("%d",&produce);
printf("\nEnter the no of consumers: ");
scanf("%d",&consume);
putchar('\n');
for (i=0; i < buff_size; i++)
buffer[i] = -1;
for (i=0; i < buff_size; i++)
printf("[%d] ", buffer[i]);
printf("\n");
initializeData();
for (i = 0; i < produce; i++)
{
pthread_create(&prod[i], NULL, producer, NULL);
produce_count++;
}
for (i = 0; i < consume; i++)
{
pthread_create(&cons[i], NULL, consumer, NULL);
consume_count++;
printf("AAAAA");
}
/*for (i = 0; i < produce; i++)
pthread_join(producer, NULL);
for (i = 0; i < consume; i++)
pthread_join(consumer, NULL);*/
printf("\n===============\n[ PRODUCED: %d ]", produce_count);
printf("\n[ CONSUMED: %d ]\n==============", consume_count);
}
pthread_create(&prod[i], NULL, producer, NULL);
In this call pthread_create will create new thread and try to return thread id in prod[i]
But:
pthread_t *prod;//thread ID
pthread_t *cons;//thread ID
These are uninitiaised pointers, if you want to collect threadids in them, you need to allocate memory to them with malloc like:
prod = malloc(sizeof(pthread_t) * produce);
cons = malloc(sizeof(pthread_t) * consume);
Otherwise pthread_create will be storing threadid in invalid memory leading to segment fault
Related
I'm trying to solve the producer consumer problem in c using threads, semaphores and mutex.
Here is my code :
Initialization :
sem_t empty;
sem_t full;
int ip = 0;
int ic = 0;
int *buffer;
pthread_mutex_t mutex;
Producer :
void* producer( void* pid) {
int x;
while(1){
srand(time(NULL));
x = (rand()%9) + 1;
sem_wait(&empty);
pthread_mutex_lock(&mutex);
buffer[ip] = x;
printf("producer %d : Inserts item %d at %d \n", *((int *) pid), buffer[ip], ip);
ip = (ip + 1) % sizeof(buffer)/sizeof(int);
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
return NULL;
}
Consumer :
void* consumer(void *cid) {
int x;
while(1){
sem_wait(&full);
pthread_mutex_lock(&mutex);
x = buffer[ic];
printf("consumer %d : gets item %d from %d \n", *(int *) cid, x, ic);
ic = (ic + 1) % sizeof(buffer)/sizeof(int);
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
return NULL;
}
Main :
int main(int argc, char* argv[]) {
int nbProducers = atoi(argv[1]);
int nbConsumers = atoi(argv[2]);
int bufferSize = atoi(argv[3]);
pthread_t producers[nbProducers];
pthread_t consumers[nbConsumers];
pthread_mutex_init(&mutex, NULL);
sem_init(&empty, 0, bufferSize);
sem_init(&full, 0, 0);
buffer = malloc(bufferSize * sizeof(int));
for(int i = 0 ; i < nbProducers ; i++)
{
pthread_create(&producers[i], NULL, (void *)producer, NULL);
}
for(int i = 0 ; i < nbConsumers ; i++)
{
pthread_create(&consumers[i], NULL, (void *)consumer, NULL);
}
for(int i = 0 ; i < nbproducers ; i++)
{
pthread_join(producers[i], NULL);
}
for(int i = 0 ; i < nbconsumers ; i++)
{
pthread_join(consumers[i], NULL);
}
pthread_mutex_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
free(buffer);
return 0;
}
I am supposed to precise how much producers and consumers I want, as well as the buffer size.
My problem is that I have a segmentation fault, and I found that it occurs when initializing the first semaphore at this line in the main : sem_init(&empty, 0, bufferSize);
I don't understand why, is it because I haven't tested argc ?
Thank you in advance.
Hi I am bit new to C programming. Facing problem with producer consumer problem. When ever I try running the below code i get segmentation fault (core dumped). Please suggest where I am going wrong. But this code works for one consumer but for multiple consumer it is throwing error.
Code:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#define MAXNITEMS 20
#define MAXNTHREADS 5
void *produce(void *arg);
void *consume(void *arg);
/* globals shared by threads */
int nitems=MAXNITEMS; /* read-only by producer and consumer */
int buff[MAXNITEMS];
int Nsignals;
struct {
pthread_mutex_t mutex;
int buff[MAXNITEMS];
int nput; /* next index to store */
int nval; /* next value to store */
} put = { PTHREAD_MUTEX_INITIALIZER };
/** struct put is used by producer only ***/
struct{
pthread_mutex_t mutex;
pthread_cond_t cond;
int nready; /* number ready for consumer */
} nready = {PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER,0};
int main(int argc, char **argv)
{
int i, prod, con;
pthread_t tid_produce[MAXNTHREADS], tid_consume[MAXNTHREADS];
printf("Enter the number of producers : \n");
scanf("%d",&prod);
printf("Enter the number of consumers: \n");
scanf("%d",&con);
/* create all producers and consumers */
for (i = 0; i < prod; i++)
{
printf("1 %d\n", i);
pthread_create(&tid_produce[i], NULL,produce, NULL);
}
for (i = 0; i < con; i++) {
printf("2 %d\n", i);
pthread_create(&tid_consume[i], NULL, consume, NULL);
}
for (i = 0; i < prod; i++) {
printf("3 %d\n", i);
pthread_join(tid_produce[i], NULL);
}
for (i = 0; i < con; i++) {
printf("4 %d\n", i);
pthread_join(tid_consume[i], NULL);
}
exit(0);
}
void *produce(void *arg)
{
for ( ; ; )
{
pthread_mutex_lock(&put.mutex);
if (put.nput >= nitems) {
pthread_mutex_unlock(&put.mutex);
return(NULL); /* array is full, we're done */
}
put.buff[put.nput] = put.nval;
printf ("producer %lu produced :%d \n",pthread_self(), put.buff[put.nput]);
put.nput++;
put.nval++;
printf("outside producer lock\n");
pthread_mutex_unlock(&put.mutex);
*((int *) arg) += 1;
}
}
void *consume(void *arg)
{
int i;
for (i = 0; i < nitems; i++) {
pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0){
pthread_cond_wait(&nready.cond,&nready.mutex);
}
printf ("consumer %lu consumed %d \n", pthread_self(),nready.nready);
nready.nready--;
pthread_mutex_unlock(&nready.mutex);
if (buff[i] != i)
printf("buff[%d] = %d\n", i, buff[i]);
}
return(NULL);
}
*((int *) arg) += 1 inside produce(...) causes the segmentation fault. Because pthread_create(&tid_produce[i], NULL,produce, NULL); passes NULL as arg.
So we need to allocate some memory for arg.
// main
int i, prod, con;
pthread_t tid_produce[MAXNTHREADS], tid_consume[MAXNTHREADS];
int p_arg[MAXNTHREADS]; // <======
// ...
for (i = 0; i < prod; i++)
{
pthread_create(&tid_produce[i], NULL,produce, p_arg+i); // <====
}
I am writing a multi-threaded application that reads a file and seeks for a word in chunks of it a thread has in memory.
A thread needs to asynchronously close other threads looking for that word if it is first to find it.
The problem is when a word is found and other threads are being closed the program does not terminate (in 6 out of 10 executions). I have checked in gdb that one thread does not exit. It happens even when I do not call waitforthreads(n_threads).
// [...]
FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads;
int allread;
// [...]
int main(int argc, char* argv[]) {
// [...]
threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
pthread_mutex_init(&mutex, NULL);
runthreads(f, word, n_threads, n_records);
waitforthreads(n_threads);
pthread_mutex_destroy(&mutex);
// [...]
}
void runthreads(FILE* f, char* w, int n_threads, int n_records) {
struct targs_t args = {w, n_records};
for (int i=0; i<n_threads; i++)
pthread_create(&threads[i], NULL, findword, (void*) &args);
}
void waitforthreads(int N) {
for (int i=0; i<N; i++)
if(pthread_join(threads[i], NULL))
exit_(6);
}
void* findword(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
struct targs_t* args = (struct targs_t*) arg;
int max_length = args->n_records * sizeof(record_t);
record_t* records = malloc(max_length);
int found = 0;
while (!allread && !found) {
pthread_mutex_lock(&mutex);
// allread is being set in the function below
// if the whole file has been read
readRecords((char*) records, args->n_records, f);
pthread_mutex_unlock(&mutex);
for (int i=0; i<args->n_records; i++)
if (strlen(records[i].text) == 0) break;
else if (strstr(records[i].text, args->word) != NULL) {
notifyfound(pthread_self(), records[i].id);
found = 1;
break;
}
}
free(records);
return NULL;
}
void notifyfound(pthread_t tid, int id) {
printf("Found: %d (%ld)\n", id, (long) tid);
for (int i=0; i<n_threads; i++)
if (threads[i] && !pthread_equal(threads[i], tid)) {
printf(" closing %ld\n", (long) threads[i]);
pthread_cancel(threads[i]);
}
printf(" finished closing\n");
}
This has to do with cancellation points, although the specifics are hard to come by since you haven't shared a minimal example. My diagnosis is either
6/10 times you have at least one thread waiting for a mutex, and other one in readRecords, which will cancel and not free the mutex. Setup cancellation handlers with pthread_cleanup_push and pthread_cleanup_pop which will free your mutex, and read the manual for pthread_cancel. See related pthread_cleanup_push causes Syntax error for some references.
Some of your threads are not detecting the cancellation - try using pthread_testcancel to setup a guaranteed cancellation point.
Here is some code that fixes these sorts of problems, by adding a cancellation check and mutex cleanup.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads = 3;
int allread;
long int count = 0;
int *thread_ids;
int global_quit = 0;
#define MAX 99999
void waitforthreads(int N) {
printf("waiting for %d threads\n", N);
for (int i=0; i<N; i++)
{
printf("thread %d | %d\n", i, threads[i]);
if(pthread_join(threads[i], NULL))
{
printf("problem\n");
exit(6);
}
}
printf("done.\n");
}
void notifyfound(pthread_t tid, int count) {
printf("%d | %d got big number\n", count, pthread_self());
for (int i=0; i<n_threads; i++)
if (threads[i] && !pthread_equal(threads[i], tid)) {
printf(" closing '%ld'\n", (long) threads[i]);
pthread_cancel(threads[i]);
}
global_quit = 1;
printf(" finished closing\n");
}
void waiting_thread_cleanup(void *arg)
{
pthread_mutex_unlock((pthread_mutex_t *)arg);
}
void* do_thing(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
int* id = (int *)arg;
int quit = 0;
while (!allread) {
pthread_mutex_lock(&mutex);
pthread_cleanup_push(waiting_thread_cleanup, (void *)&mutex); /* must be paired with pop. */
if(count++==MAX)
{
notifyfound(pthread_self(), *id);
quit=1;
}
else if(count % 10000 == 0)
printf("[%d] - %d\n", *id, count);
pthread_testcancel(); /* required to allow for the cancel to ever be 'detected' other functions are sufficient as well. */
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(1); /* if this isn't here, this will occassionally hand because the mutex isn't freed. */
if(quit==1)
{
printf("%d | %d quitting\n", *id, pthread_self());
break;
}
}
return NULL;
}
void runthreads(FILE* f, int n_threads) {
for (int i=0; i<n_threads; i++)
pthread_create(&threads[i], NULL, do_thing, &(thread_ids[i]));
}
int main(int argc, char* argv[]) {
threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
thread_ids = (int*) calloc(n_threads, sizeof(int));
for(int i=0;i<n_threads;i++)
thread_ids[i] = i;
pthread_mutex_init(&mutex, NULL);
runthreads(f, n_threads);
waitforthreads(n_threads);
pthread_mutex_destroy(&mutex);
}
The entire implementation of the critical section using semaphore is what i tried to implement.
The entire code using semaphores is shown:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
int buf[256];
int in = 0;
int out = 0;
sem_t full;
sem_t empty;
sem_t mutex;
int buf_size;
int counter = 0;
void *producer(void *arg)
{
int i, item, *index;
index = (int *)arg;
for (i = 0;; i++)
{
item = 1000 + i;
sem_wait(&empty);
sem_wait(&mutex);
buf[in] = item;
in = (in + 1) % (*index);
counter++;
printf("\n%d [P%d] ", item, *index);
sem_post(&mutex);
sem_post(&full);
/* if (i % 5 == 0)
sleep(1); */
}
}
void *consumer(void *arg)
{
int i, item, *index;
index = (int *)arg;
for (i = 0;;i++)
{
sem_wait(&full);
sem_wait(&mutex);
item = buf[out];
out = (out + 1) % (*index);
counter--;
printf("\n%d [C%d] ", item, *index);
sem_post(&mutex);
sem_post(&empty);
/* if (i % 5 == 0)
sleep(1); */
}
}
int main()
{
int produce, consume;
int i;
printf("\nThe Buffer Size:");
scanf("%d", &buf_size);
printf("\nThe Producer:");
scanf("%d", &produce);
printf("\nThe Consumer:");
scanf("%d", &consume);
pthread_t prod, cons;
void* exit_status;
sem_init(&full, 0, 0);
sem_init(&empty, 0, buf_size);
sem_init(&mutex, 0, 1);
for (i = 0; i < produce; i++)
{
pthread_create(&prod, NULL, producer, &i);
}
for (i = 0; i < consume; i++)
{
pthread_create(&cons, NULL, consumer, &i);
}
pthread_join(prod, &exit_status);
pthread_join(cons, &exit_status);
// pthread_exit(NULL);
return 0;
}
The code compiles without error but the output is nothing but the inputs that it takes and then thit just shows 1000 and p1 1001 p2 and values like that
You create your first producer and then immediately wait for it to terminate with join(), so blocking your main thread. That producer runs in its for loop, pushing the queue until the 'empty' semaphore has no more units and the producer then blocks.
The main and one producer thread are now both stuck. The other producers, and all the consumers, are never started. No consumers means nothing to pop from the queue, so the whole lot is deadlocked.
This is not untypical when using join().
I wrote this code in order to better understand producer consumer in a program where I require threads to wait for a task and then work in parallel to complete it.
I am wondering if I really needed an array for the conditionMet integer variables?
Could I not do the same with one integer?
Was there anything I could do to simplify the code?
My goal is to allow the main thread to hand tasks to the other threads.
Since this is just the skeleton, I am wondering if there is a way to simplify it?
#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define NTHREADS 7
#define RUN_N_TIMES 3
pthread_cond_t new_task_available = PTHREAD_COND_INITIALIZER;
pthread_cond_t task_complete = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
volatile int producerCond = 0;
volatile int conditionMet[NTHREADS] = {};
volatile int no_more_tasks = 0;
volatile int mini_tasks_complete = - NTHREADS;
void do_work(unsigned int* current_level){
++*current_level;
printf("Thread %u has completed %u units of work.\nIt was #%d to complete it's task this round..\n", (unsigned int)pthread_self(), *current_level, mini_tasks_complete);
}
void *threadfunc(void *parm)
{
int* thread_cond;
unsigned int level = 0;
thread_cond = (int*)parm;
while(!no_more_tasks){
pthread_mutex_lock(&mutex);
++mini_tasks_complete;
if(mini_tasks_complete == NTHREADS){
producerCond = 1;
pthread_cond_signal(&task_complete);
}
threads_waiting++;
*thread_cond = 0;
while (!*thread_cond) {
pthread_cond_wait(&new_task_available, &mutex);
if(no_more_tasks)
{
pthread_mutex_unlock(&mutex);
return NULL;
}
}
pthread_mutex_unlock(&mutex);
do_work(&level);
}
return NULL;
}
void reset_cond(int val){
int i;
for (i=0; i<NTHREADS; ++i)
conditionMet[i] = val;
}
int main(int argc, char **argv)
{
int i;
pthread_t threadid[NTHREADS];
for(i=0; i < NTHREADS; ++i) {
pthread_create(&threadid[i], NULL, threadfunc, &(conditionMet[i]));
}
while(threads_waiting < NTHREADS)
sleep(1); /* Sleep is not a very robust way to serialize threads */
/* The condition has occured. Set the flag and wake up any waiting threads */
printf("Waking up all waiting threads " "#RUN_N_TIMES" " times...\n");
for(i = 0; i < RUN_N_TIMES; i++){
pthread_mutex_lock(&mutex);
mini_tasks_complete = 0;
printf("New tasks available.\n");
sleep(1);
reset_cond(1);
pthread_cond_broadcast(&new_task_available);
producerCond = 0;
while (!producerCond) {
printf("Main waiting\n");
pthread_cond_wait(&task_complete, &mutex);
}
pthread_mutex_unlock(&mutex);
}
no_more_tasks = 1;
pthread_mutex_lock(&mutex);
mini_tasks_complete = 0;
printf("Go home everybody!\n");
pthread_cond_broadcast(&new_task_available);
pthread_mutex_unlock(&mutex);
printf("Wait for threads and cleanup\n");
for (i=0; i<NTHREADS; ++i) {
pthread_join(threadid[i], NULL);
}
pthread_cond_destroy(&new_task_available);
pthread_cond_destroy(&task_complete);
pthread_mutex_destroy(&mutex);
printf("Main done\n");
return 0;
}