void process(int number, int time) {
printf("Prosess %d kjører\n", number);
sleep(time);
printf(" Prosess %d terminated after %d sekunder\n", number, time);
}
int main(void) {
pid_t pid[7];
int status= 0;
if((pid[1]= fork())== 0) {
process(1, 1);
exit(0);
}
if((pid[3]= fork())== 0) {
process(3, 3);
exit(0);
}
waitpid(pid[1], NULL, 0);
if((pid[5]= fork())== 0) {
process(5, 3);
exit(0);
}
if((pid[2]= fork())== 0) {
process(2, 2);
exit(0);
}
waitpid(pid[3], NULL, 0);
//waitpid(pid[2], NULL, 0);
if((pid[4]= fork())== 0) {
process(4, 2);
exit(0);
}
waitpid(pid[5], NULL, 0);
if((pid[6]= fork())== 0) {
process(6, 3);
exit(0);
}
wait(NULL);
while(wait(&status)> 0) {
//We just wait for the children to finish their processes
}
printf("All processes is now terminated\n");
return 0;
}
How can I turn this code to do the same, but instead use pthread and mutex?? We're asked to make a struct method with id (There shall be 6 threads, wich each sleep a different times.), sec (sleeptime) and int signal[6].
Its a school task, and we dont get any c-training. Please help.
You would synchronize access to any shared data between the different threads by the same mutex and you would then do a join_all in the main thread to wait for all threads to finish.
I leave implementation up to the reader.
sem_t sem[6]; /* one semaphore for each thread */
struct threadargs {
int id; /* thread number */
int sec; /* how many seconds to sleep */
int signal[6]; /* which threads to signal when done */
};
void* tfunc(void *arg) {
int i;
struct threadargs *targs=arg;
// VENT PÅ DIN EGEN SEMAFOR
sem_wait(&sem[targs->id-1]);
printf("Tråd %d kjører\n", targs->id);
sleep(targs->sec);
printf("Tråd %d er ferdig og vekker kanskje andre...\n", targs->id);
// ITERATE OVER Signal-array and wake up thread nr "i" if Signal[i] is 1
for(i= 0; i< 6; i++) {
if(targs->signal[i]== 1)
sem_post(&sem[i]);
}
}
int main(void)
{
int i,j;
pthread_t tid[6];
struct threadargs *targs[6];
/* allocate memory for threadargs and zero out semaphore signals */
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; /* thread number 1 */
targs[0]->sec=1; /* how long to sleep */
targs[0]->signal[1]=1; /* which threads to wake up when done */
targs[0]->signal[4]=1;
// INITIALIZES THREADS SEMAPHORE TO 1 OR 0
sem_init(&sem[0], SHARED, 1);
// START THREAD
pthread_create(&tid[0], NULL, tfunc, (void*) targs[0]);
targs[1]->id= 2; /* thread number 2 */
targs[1]->sec=2; /* how long to sleep */
targs[1]->signal[3]=1; /* which threads to wake up when done */
sem_init(&sem[1], SHARED, 0);
pthread_create(&tid[1], NULL, tfunc, (void*) targs[1]);
targs[2]->id= 3; /* thread number 3 */
targs[2]->sec=3; /* how long to sleep */
sem_init(&sem[2], SHARED, 0);
pthread_create(&tid[2], NULL, tfunc, (void*) targs[2]);
targs[3]->id= 4; /* thread number 4 */
targs[3]->sec=2; /* how long to sleep */
sem_init(&sem[3], SHARED, 0);
pthread_create(&tid[3], NULL, tfunc, (void*) targs[3]);
targs[4]->id= 5; /* thread number 5 */
targs[4]->sec=3; /* how long to sleep */
targs[4]->signal[5]=1; /* which threads to wake up when done */
sem_init(&sem[4], SHARED, 0);
pthread_create(&tid[4], NULL, tfunc, (void*) targs[4]);
targs[5]->id= 6; /* thread number 6 */
targs[5]->sec=3; /* how long to sleep */
sem_init(&sem[5], SHARED, 0);
pthread_create(&tid[5], NULL, tfunc, (void*) targs[5]);
for(i=0;i<6;i++)
pthread_join(tid[i], NULL);
return 0;
}
This is the code I used. Pthreads with semaphores =)
Thank you for your help!
Related
I am testing a signal handler for my OS Class project.
Basically my signal handler (which is running in it's own thread) have to handle SIGINT, this means that it has to "kill" all the other threads and then exit.
unfortunately my code does not work.
This is my dummy thread task, which I want to stop with a SIGINT
static void * dummyTask(){
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
while(1){
pthread_testcancel();
printf(" Hello!\n");
sleep(2);
}
return NULL;
}
Here is my main. As you can see I create the signal handler and then up to 2 dummy threads.
I save their thID in an array, I need this later in the task of the signal handler thread, as you will see
int main(){
//need to the signal handler thread, so it can kill all the threads with cancel
pthread_t **thids = malloc( 2 * sizeof(pthread_t *));
sigset_t set;
pthread_t signalHandlerThread;
sigemptyset(&set);
sigaddset(&set, SIGINT);
//s is for error checking, not importanto now
int s = pthread_sigmask(SIG_BLOCK, &set, NULL);
//shParam: signalHandlerParam
signalHParam *shParam = malloc(sizeof(signalHParam));
shParam->set = &set;
shParam->arrayOfThIDs = thids;
s = pthread_create(&signalHandlerThread, NULL, signalHandlerTask, (void *) shParam);
for(int i = 0; i < 2; i ++){
pthread_t dummyThread;
pthread_create(&dummyThread, NULL, &dummyTask, NULL);
thids[i] = &dummyThread;
}
pause();
//pthread_join(signalHandlerThread, NULL);
return 1;
}
As you can see the signalHandlerThread execute a function named signalHandlerTask, which is:
static void *signalHandlerTask(void *shParam){
signalHParam *tmp = (signalHParam *) shParam;
sigset_t *set = tmp->set;
int s, sig;
int i = sigismember(set, SIGINT);
if(i != 1)
printf("error\n");
while(1 == 1){
s = sigwait(set, &sig);
if(sig == SIGINT){
printf("\n----- signal recived ----\n");
//function that use the array to kill threads
killThreads(tmp->arrayOfThIDs);
pthread_exit(NULL); //kill the signal handler thread
}
}
}
The shParam is a struct that I use to pass multiple arguments to the task of the thread (signalHandlerTask) and it is like this
typedef struct{
pthread_t **arrayOfThIDs;
sigset_t *set;
} signalHParam;
Finally we are at the real issue. I created the killThreads function as follows:
void killThreads(pthread_t **thids){
for(int i = 0; i < 2; i++){
int r = pthread_cancel(*thids[i]);
if(r != 0)
printf("error!! %d\n", r);
//r is 3, why??
pthread_join(*thids[i], NULL);
}
}
The problem is, as said, that pthread_cancel(*thids[i]) not work, threads are left alive and I can't figure out why
Here is the entire code for those who wants to run it:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <error.h>
#include <unistd.h>
#include <errno.h>
typedef struct{
pthread_t **arrayOfThIDs;
sigset_t *set;
} signalHParam;
void killThreads(pthread_t **thids){
//termino il threadListener, e tutti i thread nel thread pool
for(int i = 0; i < 2; i++){
//FAI ANCHE SU PROGETTO!!
int r = pthread_cancel(*thids[i]);
if(r != 0)
printf("pthread_cancel failed: %s\n", strerror(r));
//FAI ANCHE SU PROGETTO!!
pthread_join(*thids[i], NULL);
}
}
static void *signalHandlerTask(void *shParam){
signalHParam *tmp = (signalHParam *) shParam;
sigset_t *set = tmp->set;
int s, sig;
int i = sigismember(set, SIGINT);
if(i != 1)
printf("error\n");
while(1 == 1){
s = sigwait(set, &sig);
if(sig == SIGINT){
printf("\n----- signal recived ----\n");
//function that use the array to kill threads
killThreads(tmp->arrayOfThIDs);
pthread_exit(NULL); //kill the signal handler thread
}
}
}
static void * dummyTask(){
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
//printf("mo aspetto 10s\n");
//sleep(10);
while(1){
pthread_testcancel();
printf(" Ciao!\n");
sleep(2);
}
return NULL;
}
int main(){
//need to the signal handler thread, so it can kill all the threads with cancel
pthread_t **thids = malloc( 2 * sizeof(pthread_t *));
sigset_t set;
pthread_t signalHandlerThread;
sigemptyset(&set);
sigaddset(&set, SIGINT);
//s is for error checking, not importanto now
int s = pthread_sigmask(SIG_BLOCK, &set, NULL);
//shParam: signalHandlerParam
signalHParam *shParam = malloc(sizeof(signalHParam));
shParam->set = &set;
shParam->arrayOfThIDs = thids;
s = pthread_create(&signalHandlerThread, NULL, signalHandlerTask, (void *) shParam);
for(int i = 0; i < 2; i ++){
pthread_t dummyThread;
pthread_create(&dummyThread, NULL, &dummyTask, NULL);
thids[i] = &dummyThread;
}
pthread_join(signalHandlerThread, NULL);
return 1;
}
Having run the full program myself, it turns out that the only important bug is the one I originally pointed out in the comments. (There are a bunch of style problems and places where I wouldn't have done it that way, but none of them rises to the level of "bug". There is one minor unrelated bug: you forgot to include stdio.h and signal.h.)
for(int i = 0; i < 2; i ++){
pthread_t dummyThread;
pthread_create(&dummyThread, NULL, &dummyTask, NULL);
thids[i] = &dummyThread;
}
This creates a single variable named dummyThread (whether or not it is declared inside the loop) and writes all of the thread handles into that variable. All of the thids[i] pointers are set to point to that one variable. Since a single pthread_t variable can only hold a single thread handle, you lose the thread handles created on all but the last iteration of the loop. Later, the signal handler thread will attempt to cancel the same thread repeatedly, will succeed the first time, and fail the remaining N-1 times. (To make it more obvious what's going on, increase the number of threads and notice that the program prints "pthread_cancel failed: No such process" exactly N-1 times, no matter what N is.)
The correction is simply to use an array of pthread_t instead of an array of pthread_t *, and write the thread handles directly into the array:
typedef struct{
pthread_t *arrayOfThIDs;
sigset_t *set;
} signalHParam;
void killThreads(pthread_t **thids){
//termino il threadListener, e tutti i thread nel thread pool
for(int i = 0; i < 2; i++){
//FAI ANCHE SU PROGETTO!!
int r = pthread_cancel(thids[i]);
if(r != 0)
printf("pthread_cancel failed: %s\n", strerror(r));
//FAI ANCHE SU PROGETTO!!
pthread_join(*thids[i], NULL);
}
}
// ...
int main(){
//need to the signal handler thread, so it can kill all the threads with cancel
pthread_t *thids = malloc( 2 * sizeof(pthread_t));
sigset_t set;
pthread_t signalHandlerThread;
sigemptyset(&set);
sigaddset(&set, SIGINT);
//s is for error checking, not importanto now
int s = pthread_sigmask(SIG_BLOCK, &set, NULL);
//shParam: signalHandlerParam
signalHParam *shParam = malloc(sizeof(signalHParam));
shParam->set = &set;
shParam->arrayOfThIDs = thids;
s = pthread_create(&signalHandlerThread, NULL, signalHandlerTask,
(void *) shParam);
for(int i = 0; i < 2; i ++){
pthread_create(&thids[i], NULL, &dummyTask, NULL);
}
pthread_join(signalHandlerThread, NULL);
return 1;
}
signalHandlerTask and dummyTask are basically correct as-is.
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;
}
I'm currently working on custom thread scheduler project that uses pthreads in C. I have been struggling conceptually with it but am finally getting the behavior I expect to see, save for the segmentation fault.
My job is to register five child threads and schedule each one based on the order of their IDs stored in an array. What I do is call pthread_mutex_lock and tell whichever child thread that is not to be scheduled first to wait. I do some stuff to my counter to keep track of when the next child should be scheduled and after one child thread increments counter to five it should wake up other threads and do the same thing for as many times as main loop is defined.
all variables:
#define NTHREADS 5 /* Number of child threads */
#define NUM_LOOPS 10 /* Number of local loops */
#define SCHEDULE_INTERVAL 1 /* thread scheduling interval */
#define errexit(code,str) fprintf(stderr,"%s: %s\n",(str),strerror(code));exit(1);
int schedule_vector[NTHREADS]; /* The thread schedule vector */
int flag = 0;
pthread_cond_t cv; // condtitional variable
pthread_mutex_t mtx; // mutex semaphore 1
int globalcounter = 0;
int currentThread;
#define TASK_LIMIT 6
here is parent thread:
int main(int argc,char *argv[])
{
int i;
int worker;
int ids[NTHREADS];
int errcode;
int *status;
int policy;
pthread_t threads[NTHREADS];
/* Create child threads --------------------------------------------- */
for (worker = 0; worker < NTHREADS; worker++)
{
ids[worker] = worker;
printf("creating child thread using id %d\n", worker);
/* Create a child thread ----------------------------------------- */
pthread_create (
&threads[worker],
NULL,
my_thread,
&ids[worker]);
}
/* Initialize the thread schedule vector -------------------------- */
schedule_vector[0] = 0; /* First thread to be executed (0) */
schedule_vector[1] = 1; /* Second thread to be exceuted (1) */
schedule_vector[2] = 2; /* Third thread to be executed (2) */
schedule_vector[3] = 3; /* Fourth thread to be executed (3) */
schedule_vector[4] = 4; /* Fifth thread to be executed (4) */
signal(SIGALRM, clock_interrupt_handler);
alarm(SCHEDULE_INTERVAL);
printf("handler set up\n");
/* Reap the threads as they exit ----------------------------------- */
for (worker = 0; worker < NTHREADS; worker++)
{
/* Wait for thread to terminate --- */
if (errcode=pthread_join(threads[worker],(void *) &status))
{ errexit(errcode,"pthread_join"); }
/* Check thread's exit status and release its resources -------- */
if (*status != worker)
{
fprintf(stderr,"thread %d terminated abnormally\n",worker);
exit(1);
}
}
/* The main (parent) thread terminates itself ---------------------- */
return(0);
}
Here is the child thread function:
void *my_thread(void * arg)
{
long int i;
long int counter;
int myid=*(int *) arg;
counter = 0;
printf("\nI am thread #%d\n\n", myid);
/* Main loop ------------------------------------------ */
for (i = 0; i < NUM_LOOPS; i++)
{
currentThread = myid;
pthread_mutex_lock(&mtx);
while(myid != schedule_vector[flag]){
pthread_cond_wait(&cv, &mtx);
}
counter++;
globalcounter = counter;
printf("Thread: %d is running ...\n", myid);
usleep(100000);
}
return arg;
}
and here is my interrupt handler:
void clock_interrupt_handler(void)
{
printf("scheduler started ++++++++++++++++++++++++++++++++++ \n");
if (currentThread == schedule_vector[flag]) {
printf("scheduled thread received: thread %d, and it's counter is at %d\n", currentThread, globalcounter);
while(globalcounter < TASK_LIMIT){
if(globalcounter == 5){
flag++;
pthread_cond_broadcast(&cv);
}
pthread_mutex_unlock(&mtx);
alarm(SCHEDULE_INTERVAL);
}
} else {
printf("unscheduled thread received, putting thread %d with count %d to sleep...\n", currentThread, globalcounter);
alarm(SCHEDULE_INTERVAL);
}
}
This is the output:
scheduler started ++++++++++++++++++++++++++++++++++
scheduled thread received: thread 0, and it's counter is at 1
Thread: 0 is running ...
Thread: 0 is running ...
Thread: 0 is running ...
Thread: 0 is running ...
Segmentation fault (core dumped)
It basically repeats this behavior, but for each thread. I'd like to understand what is exactly causing the seg fault
Seems pthread_mutex_lock/pthread_mutex_unlock do not pair.
The correct code looks like
pthread_mutex_lock()
pthread_cond_broadcast()
pthread_mutex_unlock()
pthread_mutex_lock()
pthread_cond_wait()
pthread_mutex_unlock()
I am trying to create a consumer-producer program where the consumer thread producer numbers to fill an array, and a consumer thread prints the numbers that populate the array. Currently, I can fill the array and pass data back and forth between the consumer/producer threads, but I want the producer to create numbers faster than the consumer processes them.
At the moment, a number is produced every 1 second, and a number is consumed every 3. Two numbers should be produced before one is consumed, but my producer thread is waiting until the number it produced is consumed.
I've tried moving around the mutex locks and unlocks, and also the signals, but I haven't gotten it to work. The following code produces the following output:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
struct Data {
int num;
int wait_time;
};
pthread_mutex_t the_mutex;
pthread_cond_t condc, condp;
//int count = 0;
struct Data buffer[32];
void* producer(void *ptr) {
int i, w; /* counter and random wait time */
struct Data data;
int count = 0;
while(1) {
//w = rand() % 5 + 3;
w = 1;
sleep(w); /* Wait between 3 and 7 seconds */
data.num = rand() % 1000; /* Create random number to pass */
//data.wait_time = rand() % 8 + 2;
data.wait_time = 3;
pthread_mutex_lock(&the_mutex); /* lock the buffer */
while (buffer[count].num != 0) { /* while full */
//pthread_cond_signal(&condc);
pthread_cond_wait(&condp, &the_mutex);
}
//pthread_mutex_lock(&the_mutex); /* lock the buffer */
buffer[count] = data;
pthread_cond_signal(&condc); /* signal consumer */
pthread_mutex_unlock(&the_mutex);
printf("Produced %i and slept for %i seconds\n", buffer[count].num, w);
if (count != 31){
count += 1;
//printf("Producer count: %i\n", count);
}
else
count = 0;
//pthread_cond_signal(&condc); /* signal consumer */
//pthread_mutex_unlock(&the_mutex); /* unlock */
}
pthread_exit(0);
}
void* consumer(void *ptr) {
int i;
int count = 0;
//for(i = 1; i <= MAX; i++) {
while(1) {
pthread_mutex_lock(&the_mutex); /* lock th buffer */
while(buffer[count].num == 0){
//pthread_cond_signal(&condp); /* while empty */
pthread_cond_wait(&condc, &the_mutex);
}
//pthread_mutex_lock(&the_mutex);
sleep(buffer[count].wait_time);
printf("Consumed %i and slept for %i seconds\n", buffer[count].num, buffer[count].wait_time);
//pthread_mutex_lock(&the_mutex);
buffer[count].num = 0;
buffer[count].wait_time = 0;
pthread_cond_signal(&condp); /* signal producer */
pthread_mutex_unlock(&the_mutex);
if(count != 31){
count += 1;
//printf("Consumer count: %i\n", count);
}
else
count = 0;
//pthread_cond_signal(&condp); /* signal producer */
//pthread_mutex_unlock(&the_mutex); /* unlock */
}
pthread_exit(0);
}
int main(int argc, char **argv) {
pthread_t pro, con;
srand(time(NULL));
for (int i = 0; i < 32; i++) { /* Initialize buffer */
buffer[i].num = 0;
buffer[i].wait_time = 0;
}
// Initialize the mutex and condition variables
/* What's the NULL for ??? */
pthread_mutex_init(&the_mutex, NULL);
pthread_cond_init(&condc, NULL); /* Initialize consumer condition variable */
pthread_cond_init(&condp, NULL); /* Initialize producer condition variable */
// Create the threads
pthread_create(&con, NULL, consumer, NULL);
pthread_create(&pro, NULL, producer, NULL);
// Wait for the threads to finish
// Otherwise main might run to the end
// and kill the entire process when it exits.
pthread_join(con, NULL);
pthread_join(pro, NULL);
//pthread_join(&con, NULL);
//pthread_join(&pro, NULL);
// Cleanup -- would happen automatically at end of program
pthread_mutex_destroy(&the_mutex); /* Free up the_mutex */
pthread_cond_destroy(&condc); /* Free up consumer condition variable */
pthread_cond_destroy(&condp); /* Free up producer condition variable */
}
Output (The program prints the 1st line after 1 seconds, then prints both the 2nd and 3rd at the same time after 3 seconds):
Produced 985 and slept for 1 seconds
Consumed 985 and slept for 3 seconds
Produced 540 and slept for 1 seconds
I would rather have the output look something like this:
Produced 985 and slept for 1 seconds
Produced 540 and slept for 1 seconds
Consumed 985 and slept for 3 seconds
The consumer is locking the mutex then sleeping for 3 seconds. So the producer is having to wait for the consumer to finish it's job/sleep before it can produce something else. Avoid sleeping either thread when a lock is in place.
EDIT:
Just edited your code a bit and this seems to work without the signals etc here. Give it a go:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
struct Data {
int num;
int wait_time;
};
pthread_mutex_t the_mutex;
pthread_cond_t condc, condp;
struct Data buffer[32];
void* producer(void *ptr) {
int i, w; /* counter and random wait time */
struct Data data;
int count = 0;
while(1) {
printf("prod count %d\n",count);
w = 1;
sleep(w);
data.num = rand() % 1000;
data.wait_time = 3;
while (buffer[count].num != 0) {
printf("buffer full, count = %d\n", count);
sleep(1);
}
// Only using the mutex when we want to change the variable.
pthread_mutex_lock(&the_mutex);
buffer[count] = data;
pthread_mutex_unlock(&the_mutex);
printf("Produced %i and slept for %i seconds\n", buffer[count].num, w);
if (count != 31){
count += 1;
}
else
count = 0;
}
pthread_exit(0);
}
void* consumer(void *ptr) {
int i;
int count = 0;
while(1) { /* lock th buffer */
printf("cons count %d\n",count);
while(buffer[count].num == 0){
printf("buffer empty, count = %d\n", count);
sleep(1);
}
sleep(buffer[count].wait_time);
printf("Consumed %i and slept for %i seconds\n", buffer[count].num, buffer[count].wait_time);
pthread_mutex_lock(&the_mutex);
buffer[count].num = 0;
buffer[count].wait_time = 0;
pthread_mutex_unlock(&the_mutex);
if(count != 31){
count += 1;
//printf("Consumer count: %i\n", count);
}
else {
count = 0;
}
}
pthread_exit(0);
}
int main(int argc, char **argv) {
pthread_t pro, con;
srand(time(NULL));
for (int i = 0; i < 32; i++) { /* Initialize buffer */
buffer[i].num = 0;
buffer[i].wait_time = 0;
}
// Initialize the mutex and condition variables
/* What's the NULL for ??? */
pthread_mutex_init(&the_mutex, NULL);
pthread_cond_init(&condc, NULL); /* Initialize consumer condition variable */
pthread_cond_init(&condp, NULL); /* Initialize producer condition variable */
// Create the threads
pthread_create(&con, NULL, consumer, NULL);
pthread_create(&pro, NULL, producer, NULL);
// Wait for the threads to finish
// Otherwise main might run to the end
// and kill the entire process when it exits.
pthread_join(con, NULL);
pthread_join(pro, NULL);
//pthread_join(&con, NULL);
//pthread_join(&pro, NULL);
// Cleanup -- would happen automatically at end of program
pthread_mutex_destroy(&the_mutex); /* Free up the_mutex */
pthread_cond_destroy(&condc); /* Free up consumer condition variable */
pthread_cond_destroy(&condp); /* Free up producer condition variable */
}
I have the following code but the producer and consumer code don't appear. It just prints "Exit the program". It's like the consumer and producer functions are never executed. I don't understand why this is happening. Can anyone explain why?
The code is as follows:
/* buffer.h */
typedef int buffer_item;
#define BUFFER_SIZE 18
/* main.c */
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
/* #include "buffer.h" */
#define RAND_DIVISOR 100000000
#define TRUE 1
/* The mutex lock */
pthread_mutex_t mutex;
/* the semaphores */
sem_t full, empty;
/* the buffer */
buffer_item buffer[BUFFER_SIZE];
/* buffer counter */
int counter;
pthread_t tid; //Thread ID
pthread_attr_t attr; //Set of thread attributes
void *producer(void *param); /* the producer thread */
void *consumer(void *param); /* the consumer thread */
void initializeData()
{
/* Create the mutex lock */
pthread_mutex_init(&mutex, NULL);
/* Create the full semaphore and initialize to 0 */
sem_init(&full, 0, 0);
/* Create the empty semaphore and initialize to BUFFER_SIZE */
sem_init(&empty, 0, BUFFER_SIZE);
/* Get the default attributes */
pthread_attr_init(&attr);
/* init buffer */
counter = 0;
}
/* Producer Thread */
void *producer(void *param)
{
buffer_item item;
while(TRUE)
{
/* sleep for a random period of time */
int rNum = rand() / RAND_DIVISOR;
sleep(rNum);
/* generate a random number */
item = rand();
/* acquire the empty lock */
sem_wait(&empty);
/* acquire the mutex lock */
pthread_mutex_lock(&mutex);
if (insert_item(item))
fprintf(stderr, " Producer report error condition\n");
else
printf("producer produced %d\n", item);
/* release the mutex lock */
pthread_mutex_unlock(&mutex);
/* signal full */
sem_post(&full);
}
}
/* Consumer Thread */
void *consumer(void *param)
{
buffer_item item;
while(TRUE) {
/* sleep for a random period of time */
int rNum = rand() / RAND_DIVISOR;
sleep(rNum);
/* aquire the full lock */
sem_wait(&full);
/* aquire the mutex lock */
pthread_mutex_lock(&mutex);
if (remove_item(&item)) {
fprintf(stderr, "Consumer report error condition\n");
} else {
printf("consumer consumed %d\n", item);
}
/* release the mutex lock */
pthread_mutex_unlock(&mutex);
/* signal empty */
sem_post(&empty);
}
}
/* Add an item to the buffer */
int insert_item(buffer_item item)
{
/* When the buffer is not full add the item
and increment the counter*/
if (counter < BUFFER_SIZE) {
buffer[counter] = item;
counter++;
return 0;
} else { /* Error the buffer is full */
return -1;
}
}
/* Remove an item from the buffer */
int remove_item(buffer_item *item)
{
/* When the buffer is not empty remove the item
and decrement the counter */
if (counter > 0) {
*item = buffer[(counter-1)];
counter--;
return 0;
} else { /* Error buffer empty */
return -1;
}
}
int main(int argc, char *argv[])
{
/* Loop counter */
int i;
/* Verify the correct number of arguments were passed in */
if(argc != 4) {
fprintf(stderr, "USAGE:./main.out <INT> <INT> <INT>\n");
}
int mainSleepTime = atoi(argv[1]); /* Time in seconds for main to sleep */
int numProd = atoi(argv[2]); /* Number of producer threads */
int numCons = atoi(argv[3]); /* Number of consumer threads */
/* Initialize the app */
initializeData();
/* Create the producer threads */
for(i = 0; i < numProd; i++) {
/* Create the thread */
pthread_create(&tid,&attr,producer,NULL);
}
/* Create the consumer threads */
for(i = 0; i < numCons; i++) {
/* Create the thread */
pthread_create(&tid,&attr,consumer,NULL);
}
/* Sleep for the specified amount of time in milliseconds */
sleep(mainSleepTime);
/* Exit the program */
printf("Exit the program\n");
exit(0);
}
First you need to apply different tid's for your threads.
pthread_t tid1, tid2;
Then use these tid's:
pthread_create(&tid1, &attr, producer, NULL);
pthread_create(&tid2, &attr, consumer, NULL);
Lastly, skip the sleep and join the threads.
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
I've tested it, and works on my system. Below is the working code in full.
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include "buffer.h"
#define RAND_DIVISOR 100000000
#define TRUE 1
/* The mutex lock */
pthread_mutex_t mutex;
/* the semaphores */
sem_t full, empty;
/* the buffer */
buffer_item buffer[BUFFER_SIZE];
/* buffer counter */
int counter;
pthread_t tid1, tid2; //Thread ID
pthread_attr_t attr; //Set of thread attributes
void *producer(void *param); /* the producer thread */
void *consumer(void *param); /* the consumer thread */
void initializeData() {
/* Create the mutex lock */
pthread_mutex_init(&mutex, NULL);
/* Create the full semaphore and initialize to 0 */
sem_init(&full, 0, 0);
/* Create the empty semaphore and initialize to BUFFER_SIZE */
sem_init(&empty, 0, BUFFER_SIZE);
/* Get the default attributes */
pthread_attr_init(&attr);
/* init buffer */
counter = 0;
}
/* Producer Thread */
void *producer(void *param) {
buffer_item item;
while(TRUE) {
/* sleep for a random period of time */
int rNum = rand() / RAND_DIVISOR;
sleep(rNum);
/* generate a random number */
item = rand();
/* acquire the empty lock */
sem_wait(&empty);
/* acquire the mutex lock */
pthread_mutex_lock(&mutex);
if(insert_item(item)) {
fprintf(stderr, " Producer report error condition\n");
}
else {
printf("producer produced %d\n", item);
}
/* release the mutex lock */
pthread_mutex_unlock(&mutex);
/* signal full */
sem_post(&full);
}
}
/* Consumer Thread */
void *consumer(void *param) {
buffer_item item;
while(TRUE) {
/* sleep for a random period of time */
int rNum = rand() / RAND_DIVISOR;
sleep(rNum);
/* aquire the full lock */
sem_wait(&full);
/* aquire the mutex lock */
pthread_mutex_lock(&mutex);
if(remove_item(&item)) {
fprintf(stderr, "Consumer report error condition\n");
}
else {
printf("consumer consumed %d\n", item);
}
/* release the mutex lock */
pthread_mutex_unlock(&mutex);
/* signal empty */
sem_post(&empty);
}
}
/* Add an item to the buffer */
int insert_item(buffer_item item) {
/* When the buffer is not full add the item
and increment the counter*/
if(counter < BUFFER_SIZE) {
buffer[counter] = item;
counter++;
return 0;
}
else { /* Error the buffer is full */
return -1;
}
}
/* Remove an item from the buffer */
int remove_item(buffer_item *item) {
/* When the buffer is not empty remove the item
and decrement the counter */
if(counter > 0) {
*item = buffer[(counter-1)];
counter--;
return 0;
}
else { /* Error buffer empty */
return -1;
}
}
int main(int argc, char *argv[]) {
/* Loop counter */
int i;
/* Verify the correct number of arguments were passed in */
if(argc != 4) {
fprintf(stderr, "USAGE:./main.out <INT> <INT> <INT>\n");
}
int mainSleepTime = atoi(argv[1]); /* Time in seconds for main to sleep */
int numProd = atoi(argv[2]); /* Number of producer threads */
int numCons = atoi(argv[3]); /* Number of consumer threads */
/* Initialize the app */
initializeData();
/* Create the producer threads */
for(i = 0; i < numProd; i++) {
/* Create the thread */
pthread_create(&tid1,&attr,producer,NULL);
}
/* Create the consumer threads */
for(i = 0; i < numCons; i++) {
/* Create the thread */
pthread_create(&tid2,&attr,consumer,NULL);
}
/* Sleep for the specified amount of time in milliseconds */
//sleep(mainSleepTime);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
/* Exit the program */
printf("Exit the program\n");
exit(0);
}