C++ distributed program blocking - distributed

I'm trying to do a distributed program to do a simple job (checks prime numbers) and apparently the program is falling in a blocking wait and I don't know why.It's a producer-consumer program and have to create one thread for each producers call or consumers call. Could anyone help me?
Ps: The problem is intermittent.
My code is bellow:
#include <pthread.h>
#include <iostream>
#include <atomic>
#include <time.h>
#include <mutex>
#include <semaphore.h>
#include <cmath>
using namespace std;
#define N 2 //buffer size
#define Np 1 //number of producer threads
#define Nc 8 //number of consumer threads
sem_t full, empty; //semaphores declaration
pthread_mutex_t bufferbusy, finish; //mutex declaration
long numbers[N]; //buffer declaration
int finished = 0; //flag declaration
int M = 0; //counter declaration
bool isPrime(long n){
/*checks if long n is prime*/
for (int i = 2; i < sqrt(n) ; i++)
if (n % i == 0)
return false;
return true;
}
void *producer(){
/*waits empty semaphore > 1 then puts a number in the buffer (with exclusive access)*/
while(M<10000){
sem_wait(&empty); //WAIT EMPTY
pthread_mutex_lock(&bufferbusy); //locks bufferbusy mutex to ensure exclusive access
for (int i = 0 ; i < N ; i++){ //scrolls the buffer
if (numbers[i] == 0){ //if finds an empty buffer's position
numbers[i] = rand()%10000001+1; //fit this position with a random number
break; //leave the loop
}
}
pthread_mutex_unlock(&bufferbusy); //unlock bufferbusy mutex
sem_post(&full); //SIGNAL FULL
}
pthread_mutex_lock(&finish); //locks finish mutex to ensure exclusive access
finished++; //count finished threads to measure the execution time
pthread_mutex_unlock(&finish); //unlock finish mutex
pthread_exit(NULL); //finish thread
}
void *consumer(){
/*waits full semaphore > 1 then pick up a number from the buffer (with exclusive access) to check if it's prime*/
long data; //store a buffer number
while(M<10000){
sem_wait(&full); // WAIT FULL
pthread_mutex_lock(&bufferbusy); //locks bufferbusy mutex to ensure exclusive access
for (int i = 0 ; i < N ; i++){ //scrolls the buffer
if (numbers[i] != 0){ //if finds a fited buffer position
data = numbers[i]; //save the number placed at this position
numbers[i] = 0; //clear the buffer position
M++; //increases the consume counter
break; //leave the loop
}
}
pthread_mutex_unlock(&bufferbusy); //unlock bufferbusy mutex
sem_post(&empty); //SIGNAL EMPTY
if(isPrime(data)); //checks if data number is prime
//cout << data << " is prime!" << endl;
//else
//cout << data << " is composite!" << endl;
}
pthread_mutex_lock(&finish); //locks finish mutex to ensure exclusive access
finished++; //count finished threads to measure the execution time
pthread_mutex_unlock(&finish); //unlock finish mutex
pthread_exit(NULL); //finish thread
}
int main (int argc, char *argv[]){
/*___________________________________VARIABLES___________________________________*/
srand (time(NULL)); //seed to measure the execution time
pthread_mutex_init(&bufferbusy,0); //init the bufferbusy mutex with 0
pthread_mutex_init(&finish,0); //init the finish mutex with 0
sem_init(&full, 0, 0); //init the semaphore full(second parameter means that it is only visible by this process)
sem_init(&empty, 0, N); //init the smaphore empty
pthread_t threads[Np+Nc]; //threads declaration
int rc; //handle errors on thread creating
int t; //for loop
/*_______________________________________________________________________________*/
/*_____________________________FILL BUFFER WITH ZEROS____________________________*/
for (int i = 0; i < N; i++) //scrolls the buffer
numbers[i] = 0; //fill all positions with 0
/*_______________________________________________________________________________*/
/*________________________CREATE AND EXECUTE MULTITHREADS________________________*/
clock_t tStart = clock(), tFinish; //start timer
for(t=0; t<Np; t++){ //for each Np
rc = pthread_create(&threads[t], NULL, producer, NULL); //creates a producer thread
if (rc){ //handle error on thread creating
cout << "ERROR; return code from pthread_create() is" << rc << endl;
exit(-1);
}
}
for(t=Np; t<Np+Nc; t++){ //for each Nc
rc = pthread_create(&threads[t], NULL, consumer, NULL); //create a consumer thread
if (rc){ //handle error on thread creating
cout << "ERROR; return code from pthread_create() is" << rc << endl;
exit(-1);
}
}
while (finished < Np+Nc); //blocking wait until all threads have finished
tFinish = clock(); //stop timer
sem_destroy(&full); //semaphore destructor
sem_destroy(&empty); //semaphore destructor
pthread_mutex_destroy(&bufferbusy); //mutex destructor
pthread_mutex_destroy(&finish); //mutex destructor
cout << "Done!" << endl;
cout << "Execution time:" << (double)(tFinish - tStart)/CLOCKS_PER_SEC << endl;
pthread_exit(NULL); //finish last thread
/*_______________________________________________________________________________*/
}

It's already working. Just add a sem_post() before exiting each thread to allow other threads exiting is enough to fix the problem.

Related

How to avoid worker threads being stuck in sem_wait?

I am new to semaphores and wanted to know how to avoid a situation where my worker thread (in a multiple worker single producer problem) is stuck in sem_wait(&full). I also have a mutex lock after this but I doubt that, that is where it is stuck. I know all my tasks are being completed but the threads are not exiting. The producer thread in my program stops sending data once all tasks are done.
For reference... the producer thread...
while (i<number_of_tasks)
{
TASK task;
task.start_row = i*num_of_rows;
task.num_of_rows = num_of_rows;
sem_wait(&empty);
pthread_mutex_lock(&mutex);
tasks[in] = task;
in = (in+1)%buff_size;
pthread_mutex_unlock(&mutex);
sem_post(&full);
i++;
//printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
if (counter==number_of_tasks)
break;
}
And ...the worker thread function
int i, item, index;
TASK task;
index = *((int*)arg);
int notasks1;
for (i=number_of_tasks; i > 0; i--) {
//previous code
sem_wait(&full);
pthread_mutex_lock(&mutex);
task=tasks[out];
out = (out+1)%buff_size;
//completing task code...
counter++;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
if (counter==number_of_tasks)
break;
}
printf("Worker thread %d has terminated and completed %d tasks\n",index,notasks1);
return NULL;
the full code... for reference
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include </usr/include/semaphore.h>
// for sleep
#include <unistd.h>
#include "Mandel.h"
#include "draw.h"
#define BUFF_SIZE 10 /* total number of slots */
#define NP 1 /* total number of producers */
#define NC 5 /* total number of consumers */
#define NITERS IMAGE_HEIGHT/10 /* number of items produced/consumed */
//int buf[BUFF_SIZE]; /* shared var */
//struct task for storing the tasks the current worker thread has to do
typedef struct task
{
int start_row;
int num_of_rows;
} TASK;
TASK* tasks;
int buff_size; //= 7;
//TASK buff[buff_size];
int in=0; /* buf[in%BUFF_SIZE] is the first empty slot */
int out=0; /* buf[out%BUFF_SIZE] is the first full slot */
sem_t full; /* keep track of the number of full spots */
sem_t empty; /* keep track of the number of empty spots */
int number_of_tasks;// = IMAGE_HEIGHT/20;
float *pixels;
int num_of_rows;// = 20;
int counter = 0;
// use correct type here
pthread_mutex_t mutex; /* enforce mutual exclusion to shared data */
/*void *Producer(void *arg)
{
int i =0;
while (i<number_of_tasks)
{
if (counter==number_of_tasks)
break;
TASK task;
task.start_row = i*num_of_rows;
task.num_of_rows = num_of_rows;
sem_wait(&empty);
pthread_mutex_lock(&mutex);
tasks[in] = task;
in = (in+1)%buff_size;
pthread_mutex_unlock(&mutex);
sem_post(&full);
i++;
if (counter==number_of_tasks)
break;
}
return NULL;
}*/
//function for consumer threads to accesss
void *Consumer(void *arg)
{
int i, item, index;
TASK task;
index = *((int*)arg);//getting index of thread from argument parsing it into int
int notasks1;
//for loop to complete number of tasks per thread
for (i=number_of_tasks; i > 0; i--) {
//defining start_compute and end compute to calculate time per task
struct timespec start_compute, end_compute;
float difftime;
printf("Worker(%d): Start the computation ...\n", index);
clock_gettime(CLOCK_MONOTONIC, &start_compute);
//calling sem wait to wait for producer thread to fill in tasks for worker threads. will wait if buffer is empty
sem_wait(&full);
//calling mutex lock
pthread_mutex_lock(&mutex);
//getting tasks from struct tasks array
task=tasks[out];
//incrementing to next task in buffer so that next thread accesses next task
out = (out+1)%buff_size;
//calculating pixels for image
int x, y;
//printf("start_row... %d, num_of_rows... %d\n", task.start_row, task.num_of_rows);
for (y=task.start_row; y<task.start_row+task.num_of_rows; y++)
{
for (x=0; x<IMAGE_WIDTH; x++)
{
pixels[y*IMAGE_WIDTH+x] = Mandelbrot(x, y);
}
}
//increasing counter to check if all tasks are done
counter++;
pthread_mutex_unlock(&mutex);
sem_post(&empty);//informing a producer that a task has been taken out and if tasks are left buffer is empty to add tasks
//calculating end compute and posting
clock_gettime(CLOCK_MONOTONIC, &end_compute); //end time values for the child processes
difftime = (end_compute.tv_nsec - start_compute.tv_nsec)/1000000.0 + (end_compute.tv_sec - start_compute.tv_sec)*1000.0;
printf("Worker(%d):\t...completed. Elapse time = %f ms\n",index, difftime);\
notasks1++;
printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
if (counter==number_of_tasks)
break;
}
printf("Worker thread %d has terminated and completed %d tasks\n",index,notasks1);
return NULL;
}
int main(int argc, char* args[])
{
buff_size = atoi(args[3]);
num_of_rows = atoi(args[2]);
number_of_tasks = IMAGE_HEIGHT/num_of_rows;
int number_of_workers;
number_of_workers = atoi(args[1]);
struct timespec start_time, end_time;
printf("number_of_tasks...%d\n", number_of_tasks);
pthread_t idP, idC;
int index;
sem_init(&full, 0, 0);//initializing full to zero so that consumer thread knows buffer is empty and waits for producer thread
sem_init(&empty, 0, buff_size);//initializing empty to buffer size so that producer knows to add that many tasks
pthread_mutex_init(&mutex, NULL);
int i = 0;
pixels = (float *) malloc(sizeof(float) * IMAGE_WIDTH * IMAGE_HEIGHT);//assigning pixels memory
//tasks = (TASK*) malloc (sizeof(TASK) *buff_size);
//pthread_create(&idP, NULL, Producer, NULL);
for(index=0; index<number_of_workers/*5*/; index++)
{
printf("Worker(%d): Start up. Wait for task!\n", index);
pthread_create(&idC, NULL, Consumer, (void*)&index);//creating worker threads to go to consumer function sending their index
}
tasks = (TASK*) malloc (sizeof(TASK) *buff_size);
//master/producer thread work
while (i<number_of_tasks)
{
TASK task;
task.start_row = i*num_of_rows;
task.num_of_rows = num_of_rows;
//calling sem wait if buffer is not empty
sem_wait(&empty);
pthread_mutex_lock(&mutex);
//adding tasks to struct task tasks array for worker/consumer threads to use
tasks[in] = task;
in = (in+1)%buff_size;
pthread_mutex_unlock(&mutex);
sem_post(&full);
//incrementing full so that worker threads know that buffer is not empty
i++;
//printf("%d tasks completed out of %d tasks\n", counter, number_of_tasks);
if (counter==number_of_tasks)
break;
}
//pthread_exit(NULL);
//waiting for all threads to exit
//pthread_join(idC, NULL);
//printing image
printf("Draw the image\n");
DrawImage(pixels, IMAGE_WIDTH, IMAGE_HEIGHT, "Mandelbrot demo", 3000);
return 0;
}
How to stop the worker thread from being stuck in the loop?
I know the program continues on and displays the correct result but when I call pthread_join it keeps on waiting... obviously. How to solve the issue?

Thread blocks when it isn't supposed to

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 */
}

C - synchronizing multiple threads w/ mutexs

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.

threads running simultaniously

so I want to have 3 threads that all increment a global integer. I thought that when a thread was created that it was simulair to a fork in that main would continue to execute code at the same time as the newly created thread. That's not what is happenin though, as the second and third threads are never created untill after the first thread is complete.
void * say_it( void * )
{
int count = 0;
while(BUFFER < 24)
{
//LOCK
if (pthread_mutex_lock(&output_lock) != 0)
{
perror("Could not lock output: ");
exit(-1);
}
//print message
cout << "TID: " << pthread_self() << " PID: " << "WORK IN PROGRESS " << "Buffer: " << BUFFER << endl;
BUFFER++;
//UNLOCK
if (pthread_mutex_unlock(&output_lock) != 0)
{
perror("Could not unlock output: ");
exit(-1);
}
count++;
}
//print final message
cout << "TID: " << pthread_self() << " worked on the buffer " << count << " times" << endl;
}
int main(int argc, char *argv[])
{
int num_threads = 3;
pthread_t *thread_ids;
void *p_status;
//Use unbuffered output on stdout
setvbuf(stdout, (char *) NULL, _IONBF, 0);
//Set up an output lock so that threads wait their turn to speak.
if (pthread_mutex_init(&output_lock, NULL)!=0)
{
perror("Could not create mutex for output: ");
return 1;
}
//Create 3 THREADS
thread_ids = new pthread_t[num_threads];
// generate threads
for (int i = 0; i < num_threads; i++)
{
int *arg = new int;
*arg = i;
if( pthread_create(&thread_ids[i],NULL,say_it,NULL) > 0)
{
perror("creating thread:");
return 2;
}
if (pthread_join(thread_ids[i], &p_status) != 0)
{
perror("trouble joining thread: ");
return 3;
}
}
return 0;
}
I have also experimented with placing sleep(1) in areas of the program to no success.
Can anyone explain this to me?
Thanks!
When you call pthread_join, main will block until that thread finishes. You need to create all of the threads, before calling pthread_join on the threads.
Side note: you're calling pthread_create again after the comment that says // join threads and print their return values. That all needs to be removed.
In the loop, you create a thread and then join with it, so you don't create the next thread until the first one has finished. You have no concurrency here.
The second loop of 10 looks plain wrong since you only allocated space for 3 thread ids, yet here you are creating 10 threads.
You are creating thread and waiting for the thread to complete. Move the join code out of for loop as below.
for (int i = 0; i < num_threads; i++)
{
int *arg = new int;
*arg = i;
if( pthread_create(&thread_ids[i],NULL,say_it,NULL) > 0)
{
perror("creating thread:");
return 2;
}
}
for (int i = 0; i < num_threads; i++)
{
if (pthread_join(thread_ids[i], &p_status) != 0)
{
perror("trouble joining thread: ");
return 3;
}
}

Semaphores and Deadlocks in C

I'm trying to code the producer/consumer problem using semaphores. I have 3, 1 acting as a mutex, and another 2 for the buffer which the producers and consumers can add/remove from. When adding/removing from the buffer I use the binary semaphore to lock/unlock it so that the global variables aren't subject to any race conditions. The produce semaphore represents how many spots are available in the buffer (how many things can be put into the buffer) while the consumer semaphore represents how many things can be removed from the buffer. I think my logic is wrong cause I always reach a deadlock. Also when I removed the produce and consume semaphores just to test whether or not the program does what its supposed to do, I still get race conditions even though the binary semaphore should be blocking that. What am I doing wrong?
enter code here
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
#include </usr/include/semaphore.h>
#define MAXITEMS 100
#define PRODUCER_NO 5
#define NUM_PRODUCED 5
void *producer_function (void);
void *consumer_function (void);
void add_buffer (long i);
long get_buffer ();
long sum_value = 0;
long finished_producers;
long buffer[MAXITEMS];
int size = 0;
int front, rear = 0;
pthread_t producerThread[5];
pthread_t consumerThread;
sem_t mutex, produce, consume;
int main(void)
{
int i = 0;
srand (time(NULL));
sem_init (&mutex, 0, 1);
sem_init (&produce, 0, 100);
sem_init (&consume, 0, 0);
for (i = 0; i < 5; i++)
{
pthread_create (&producerThread[i], NULL, (void *) producer_function, NULL);
}
pthread_create (&consumerThread, NULL, (void *) consumer_function, NULL);
for (i = 0; i < 5; i++)
{
pthread_join (producerThread[i], NULL);
}
pthread_join (consumerThread, NULL);
return(0);
}
void *producer_function(void)
{
long counter = 0;
long producer_sum = 0L;
while (counter < NUM_PRODUCED)
{
sem_wait (&mutex);
sem_wait (&produce);
long rndNum = rand() % 10;
producer_sum += rndNum;
add_buffer (rndNum);
sem_post (&consume);
counter++;
if (counter == NUM_PRODUCED)
{
finished_producers++;
}
sem_post (&mutex);
usleep(1000);
}
printf("--+---+----+----------+---------+---+--+---+------+----\n");
printf("The sum of produced items for this producer at the end is: %ld \n", producer_sum);
printf("--+---+----+----------+---------+---+--+---+------+----\n");
return(0);
}
void *consumer_function (void)
{
while (1)
{
sem_wait (&mutex);
sem_wait (&consume);
long readnum = get_buffer();
sem_post (&produce);
sum_value += readnum;
sem_post (&mutex);
//printf ("%ld\n", sum_value);
if ((finished_producers == PRODUCER_NO) && (size == 0))
{
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("The sum of the all produced items at the end is: %ld \n", sum_value);
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
break;
}
}
}
void add_buffer(long i){
buffer[rear] = i;
rear = (rear+1) % MAXITEMS;
size++;
}
long get_buffer(){
long v;
v = buffer[front];
front = (front+1) % MAXITEMS;
size--;
return v;
}
user2929779,
I think its essential to not have the mutex locked, when waiting for a consume notification in the consumer, or vice versa a produce notification in the producer. Imagine you're getting blocked because of waiting for a consume notification, and no producer was able to publish such a notification then your consumer keeps the mutex locked and no producer ever gets the chance to produce a new item...
So the order is important here:
1.) First wait for notification from remote side
2.) lock mutex
3.) modify global data
4.) release mutex
5.) notify remote side
Try this instead:
void *producer_function(void)
{
long counter = 0;
long producer_sum = 0L;
while (counter < NUM_PRODUCED)
{
sem_wait (&produce);
sem_wait (&mutex);
long rndNum = rand() % 10;
producer_sum += rndNum;
add_buffer (rndNum);
counter++;
if (counter == NUM_PRODUCED)
{
finished_producers++;
}
sem_post (&mutex);
sem_post (&consume);
usleep(1000);
}
printf("--+---+----+----------+---------+---+--+---+------+----\n");
printf("The sum of produced items for this producer at the end is: %ld \n", producer_sum);
printf("--+---+----+----------+---------+---+--+---+------+----\n");
return(0);
}
void *consumer_function (void)
{
while (1)
{
sem_wait (&consume);
sem_wait (&mutex);
long readnum = get_buffer();
sum_value += readnum;
if ((finished_producers == PRODUCER_NO) && (size == 0))
{
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("The sum of the all produced items at the end is: %ld \n", sum_value);
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
break;
}
sem_post (&mutex);
sem_post (&produce);
//printf ("%ld\n", sum_value);
}
return(0);
}
P.S. For now ignoring return values of system calls just to show example implementation...
P.S.S. See also pseudo code on wiki http://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem#Using_semaphores ...

Resources