Producers Consumers Threads and Mutex - c

In relation to when producer accesses the shared source, Do I need another condition variable/condition signal? So it does get blocked when the shared resource is locked. I have a condition variable for the consumer, so it does it waits and if it won't try to access if there is nothing there to be added on (to consume)
int pnum; // number updated when producer runs.
int csum; // sum computed using pnum when consumer runs.
int (*pred)(int); // predicate indicating number to be consumed
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condc,condp;
int toConsume = 0; // condition varibale counter
int produceT() {
//Start Critical Section
pthread_mutex_lock(&mutex);
scanf("%d",&pnum);
toConsume++;
//End Critical Section
pthread_cond_signal (&condc);
pthread_mutex_unlock(&mutex);
return pnum;
}
void *Produce(void *a) {
int p;
p=1;
while (p) {
printf("producer thinking...\n");
sleep(1);
printf("..done!\n");
p = produceT();
printf("PRODUCED %d\n",p);
}
printf("EXIT-P\n");
pthread_exit(0);
}
int consumeT() {
pthread_mutex_lock(&mutex); //protect buffer
while(toConsume <=0){ // if nothing in buffer then wait
pthread_cond_wait(&condc,&mutex);
}
pthread_mutex_unlock(&mutex); //release buffer
//sleep()
pthread_mutex_lock(&mutex); //protect buffer
if ( pred(pnum) ) { csum += pnum; }
toConsume--;
pthread_mutex_unlock(&mutex);
return pnum;
}
void *Consume(void *a) {
int p;
p=1;
while (p) {
printf("consumer thinking...\n");
sleep(rand()%3);
printf("..done!\n");
p = consumeT();
printf("CONSUMED %d\n",csum);
}
printf("EXIT-C\n");
pthread_exit(0);
}
int main (int argc, const char * argv[]) {
// the current number predicate
static pthread_t prod,cons;
long rc;
pred = &cond1;
if (argc>1) {
if (!strncmp(argv[1],"2",10)) { pred = &cond2; }
else if (!strncmp(argv[1],"3",10)) { pred = &cond3; }
}
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&condc,NULL);//Initialize consumer condition variable
pthread_cond_init(&condp,NULL);//Initialize producer condition variable
pnum = 999;
csum=0;
srand(time(0));
printf("Creating Producer:\n");
rc = pthread_create(&prod,NULL,Produce,(void *)0);
if (rc) {
printf("ERROR return code from pthread_create(prod): %ld\n",rc);
exit(-1);
}
printf("Creating Consumer:\n");
rc = pthread_create(&cons,NULL,Consume,(void *)0);
if (rc) {
printf("ERROR return code from pthread_create(cons): %ld\n",rc);
exit(-1);
}
pthread_join( prod, NULL);
pthread_join( cons, NULL);
printf("csum=%d.\n",csum);
return 0;
}

A conditional variable is a way of efficiently blocking a thread until a certain condition is verified.
You use a conditional variable in the consumer simply because you dictate you can't consume if there isn't anything to consume -- so you decide to block until there is something to consume. In your case, this happens when toConsume == 0.
You may dictate that the producer must also wait -- that's entirely up to your specification. Some ideas:
You may want to prevent the variable to go over a certain value (e.g. 1000, or INT_MAX to avoid overflow).
If instead of a counter you use a circular buffer to place your things to be consumed, the producer must wait if there are no free slots to place the things in the buffer. This is the most common way of teaching the producers-consumers in textbooks :)

Related

why does Pthread Signal from main, hangs the code?

The requirement for the sample application creating using pthread is given below:
A single thread is created from main using Pthread
Inside thread, Mutex is locked, a counter counts the value and while loop is incremented, While is set to the max count of 10.
after while loop finishes, the mutex is unlocked.
The above requirement I have tried implementing using pthread
Code is shown below:
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
int samples = 10;
int count = 0;
struct example
{
int i;
int a;
};
void *inc_x(void *x_void_ptr)
{
pthread_mutex_lock(&count_mutex);
printf("Thread is locked \n");
while(count < samples)
{
printf("inside While loop \n");
struct example *E2_ptr;
E2_ptr = (struct example *)x_void_ptr;
printf("inside thread count = %d\n",count);
E2_ptr->a = count;
E2_ptr->i = (count + 1);
count ++;
//pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
pthread_mutex_unlock(&count_mutex);
printf ( "\n Test Successful for Thread\n");
pthread_exit(NULL);
}
int main()
{
int x = 100, y = 0,i = 0;
struct example *E1_ptr;
E1_ptr->a = 0;
E1_ptr->i = 0;
printf("Before\t E1_ptr->a = %d\t, E1_ptr->i = %d\n",E1_ptr->a,E1_ptr->i);
pthread_t inc_x_thread;
if(pthread_create(&inc_x_thread, NULL, inc_x, E1_ptr))
{
printf("Error creating thread\n");
}
if(pthread_join(inc_x_thread, NULL))
{
printf("Error joining thread\n");
}
for(i = 0; i<(samples-1); i++)
{
if(pthread_cond_signal(&count_threshold_cv))
{
printf("Error Signaling thread at sample = %d\n",i);
}
}
printf("after\t E1_ptr->a = %d\t, E1_ptr->i = %d\n",E1_ptr->a,E1_ptr->i);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit (NULL);
return 0;
}
Doubt:
In the above code, the thread executes its function properly and exits.
Once the condition is applied, i.e. the below shown code is uncommented then,
pthread_cond_wait(&count_threshold_cv, &count_mutex);
Then the thread is stopped after 1st iteration of while loop as expected.
The signal is generated from main by the code shown below:
for(i = 0; i<(samples-1); i++)
{
if(pthread_cond_signal(&count_threshold_cv))
{
printf("Error Signaling thread at sample = %d\n",i);
}
}
observed that the signal is never sent.
Can someone please guide me, where am I going wrong. I'm a newbie to Pthreads.
Thanks in advance.
count_mutex and count_threshold_cv are not initialized, add:
int main()
{
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init(&count_threshold_cv, NULL);
//...
E1_ptr is not initialized.
There are many ways to solve it:
You can call malloc to allocate memory:
struct example *E1_ptr = malloc(sizeof(struct example));
E1_ptr->a = 0;
E1_ptr->i = 0;
or holds pointer to local variable:
struct example ex;
struct example *E1_ptr = &ex; //malloc(sizeof(struct example));
E1_ptr->a = 0;
E1_ptr->i = 0;
or
struct example ex;
ex.a = 0;
ex.i = 0;
then create thread with pthread_create(&inc_x_thread, NULL, inc_x, &ex)
pthread_cond_signal function does not wait. If a thread is blocked by condition variable pthread_cond_signal function unblocks this thread, otherwise returns immediately without waiting and does nothing. So your for loop with 10 iterations is executed as soon as possible, without any waiting for pthread_cond_wait is called.
So can rewrite your for loop to infinite loop, calling pthread_cond_signal repeatedly.
if(pthread_create(&inc_x_thread, NULL, inc_x, E1_ptr)) {
printf("Error creating thread\n");
}
while(1) { // INFINITE LOOP
if(pthread_cond_signal(&count_threshold_cv)) {
printf("Error Signaling thread at sample = %d\n",i);
}
if (taskDone) // testing global flag, if 1 break
break; // it means inc_x thread has ended
}
if(pthread_join(inc_x_thread, NULL)) { // it was pointed out in comment
printf("Error joining thread\n"); // you need to join at the end of main function
}
taskDone is global int, with 0 as default value. It is set to 1 before pthread_exit is called in inc_x function. Setting/checking taskDone should be wrapped with some synchronization mechanism, for example by adding new mutex or use count_mutex.

pthread_cond_wait and pthread_mutex_lock priority?

I have a multiple read threads and one write thread. If I lock mutex on one of the read threads and send broadcast from it, is it guaranteed that mutex will be locked by write thread waiting on pthread_cond_wait() or is there a possibility that another read thread that is wainting on pthread_mutex_lock() will lock mutex? Main question is does pthread_cond_wait() have priority over pthread_mutex_lock()?
If not, how can I achieve that the mutex will always be locked by write thread on pthread_cond_broadcast()?
Example
Read thread:
pthread_mutex_lock(mutex);
pthread_cond_broadcast(cond);
pthread_mutex_unlock(mutex);
Write thread:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
Let's assume both threads, read and write, reach the pthread_mutex_lock in the same moment. So, either write thread acquire the mutex on pthread_mutex_lock call, or read thread.
If it would be the write thread, the read one will wait on pthread_mutex_lock. The write, by calling pthread_cond_wait releases mutex and blocks on cond. It is done atomically. So, when read thread is grantex the mutex, we can be sure the the read one waits on cond. So, broadcast on cond reaches the write thread, it no more waits on cond but - still in scope of pthread_cond_wait - tries to get a lock on mutex (hold be read thread). After broadcasting cond the read thread releases the mutex and it goes to write thread. So write thread finally exits from pthread_cond_wait having the mutex locked. Remember to unlock it later.
If it would be the read thread, the write one will wait on pthread_mutex_lock, the read will broadcast a signal on cond then release the mutex. After then the write thread acquires the mutex on pthread_mutex_lock and immediately releases in it pthread_cond_wait waiting for cond (please note, that previous cond broadcast has no effect on current pthread_cond_wait). In the next iteration of read thread it acquires lock onmutex, send broadcast on cond and unlock mutex. It means the write thread moves forward on cond and acquires lock on mutex.
Does it answer your question about priority?
Update after comment.
Let's assume we have one thread (let's name it A for future reference) holding the lock on mutex and few other trying to acquire the same lock. As soon as the lock is released by first thread, there is no predictable which thread would acquire lock. Moreover, if the A thread has a loop and tries to reacquire lock on mutex, there is a chance it would be granted this lock and other threads would keep waiting. Adding pthread_cond_wait doesn't change anything in scope of granting a lock.
Let me quote fragments of POSIX specification (see https://stackoverflow.com/a/9625267/2989411 for reference):
These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.
And this is only guarantee given by standard regarding order of operations. Order of granting the lock to other threads is rather unpredictable and it changes depending on some very subtle fluctuation in timing.
For only mutex related code, please play a little with following code:
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *th(void *arg) {
int i;
char *s = arg;
for (i = 0; i < 10; ++i) {
pthread_mutex_lock(&mutex);
printf("%s %d\n", s, i);
//sleep(1);
pthread_mutex_unlock(&mutex);
#if 0
pthread_yield();
#endif
}
return NULL;
}
int main() {
int i;
for (i = 0; i < 10; ++i) {
pthread_t t1, t2, t3;
printf("================================\n");
pthread_create(&t1, NULL, th, "t1");
pthread_create(&t2, NULL, th, " t2");
pthread_create(&t3, NULL, th, " t3");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
}
return 0;
}
On one machine (single CPU) it always shows whole loop from t3, then t2 and finally from t1. On another (2 cores) the order of threads is more random, but almost always it shows whole loop for each thread before granting the mutex to other thread. Rarely there is a situation like:
t1 8
t1 9
t3 0
t2 0
t2 1
[removed other t2 output]
t2 8
t2 9
t3 1
t3 2
Enable pthread_yield by replacing #if 0 with #if 1 and watch results and check output. For me it works in a way two threads display their output interlaced, then third thread finally has a chance to work. Add another or more thread. Play with sleep, etc. It confirms the random behaviour.
If you wish to experiment a little, compile and run following piece of code. It's an example of single producer - multiple consumers model. It can be run with two parameters: first is the number of consumer threads, second is the length of produced data series. If no parameters are given there is one consumer thread and 120 items to be processed. I also recommend with sleep/usleep in places marked /* play here */: change the value of arguments, remove the sleep at all, move it - when appropriate - to critical section or replace with pthread_yield and observe changes in behaviour.
#define _GNU_SOURCE
#include <assert.h>
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
struct data_t {
int seq;
int payload;
struct data_t *next;
};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct data_t *first = NULL, *last = NULL;
int in_progress = 1;
int num_data = 120;
void push(int seq, int payload) {
struct data_t *e;
e = malloc(sizeof(struct data_t));
e->seq = seq;
e->payload = payload;
e->next = NULL;
if (last == NULL) {
assert(first == NULL);
first = last = e;
} else {
last->next = e;
last = e;
}
}
struct data_t pop() {
struct data_t res = {0};
if (first == NULL) {
res.seq = -1;
} else {
res.seq = first->seq;
res.payload = first->payload;
first = first->next;
if (first == NULL) {
last = NULL;
}
}
return res;
}
void *producer(void *arg __attribute__((unused))) {
int i;
printf("producer created\n");
for (i = 0; i < num_data; ++i) {
int val;
sleep(1); /* play here */
pthread_mutex_lock(&mutex);
val = rand() / (INT_MAX / 1000);
push(i, val);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
printf("prod %3d %3d signaled\n", i, val);
}
in_progress = 0;
printf("prod end\n");
pthread_cond_broadcast(&cond);
printf("prod end signaled\n");
return NULL;
}
void *consumer(void *arg) {
char c_id[1024];
int t_id = *(int *)arg;
sprintf(c_id, "%*s c %02d", t_id % 10, "", t_id);
printf("%s created\n", c_id);
while (1) {
struct data_t item;
pthread_mutex_lock(&mutex);
item = pop();
while (item.seq == -1 && in_progress) {
printf("%s waits for data\n", c_id);
pthread_cond_wait(&cond, &mutex);
printf("%s got signal\n", c_id);
item = pop();
}
if (!in_progress && item.seq == -1) {
printf("%s detected end of data.\n", c_id);
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
printf("%s processing %3d %3d\n", c_id, item.seq, item.payload);
sleep(item.payload % 10); /* play here */
printf("%s processed %3d %3d\n", c_id, item.seq, item.payload);
}
printf("%s end\n", c_id);
return NULL;
}
int main(int argc, char *argv[]) {
int num_cons = 1;
pthread_t t_prod;
pthread_t *t_cons;
int i;
int *nums;
if (argc > 1) {
num_cons = atoi(argv[1]);
if (num_cons == 0) {
num_cons = 1;
}
if (num_cons > 99) {
num_cons = 99;
}
}
if (argc > 2) {
num_data = atoi(argv[2]);
if (num_data < 10) {
num_data = 10;
}
if (num_data > 600) {
num_data = 600;
}
}
printf("Spawning %d consumer%s for %d items.\n", num_cons, num_cons == 1 ? "" : "s", num_data);
t_cons = malloc(sizeof(pthread_t) * num_cons);
nums = malloc(sizeof(int) * num_cons);
if (!t_cons || !nums) {
printf("Out of memory!\n");
exit(1);
}
srand(time(NULL));
pthread_create(&t_prod, NULL, producer, NULL);
for (i = 0; i < num_cons; ++i) {
nums[i] = i + 1;
usleep(100000); /* play here */
pthread_create(t_cons + i, NULL, consumer, nums + i);
}
pthread_join(t_prod, NULL);
for (i = 0; i < num_cons; ++i) {
pthread_join(t_cons[i], NULL);
}
free(nums);
free(t_cons);
return 0;
}
I hope I have cleared your doubts and gave you some code to experiment and gain some confidence about pthread behaviour.

Thread synchronisation using semaphore for c

I am writing a c program to create three threads(1,2,3) such that at any given point of time only one thread must execute and print the output on console in the order 123123123123.........
I am making use of semaphore for synchronization.
I am having an issue with the code i have written. the code doesn't print it in the order 123123... the order is random and stops after a while.
#include<stdio.h>
#include<semaphore.h>
#include<pthread.h>
#include<unistd.h>
#include<assert.h>
#include<stdlib.h>
sem_t sem_1;
void *func1(void *arg){
int err1=0;
while(1){
err1=sem_wait(&sem_1);
assert(err1==0);
printf("thread 1\n");
}
//return NULL;
}
void *func2(void *arg){
int err2=0;
while(1){
err2=sem_wait(&sem_1);
assert(err2==0);
printf("thread 2\n");
}
// return NULL;
}
void *func3(void *arg){
int err3=0;
while(1){
err3=sem_wait(&sem_1);
assert(err3==0);
printf("thread 3\n");
}
// return NULL;
}
int main(){
pthread_t *t1,*t2,*t3;
int i=0,rc=0,c1=0,c2=0,c3=0;
t1=(pthread_t *)malloc(sizeof(*t1));
t2=(pthread_t *)malloc(sizeof(*t2));
t3=(pthread_t *)malloc(sizeof(*t3));
i=sem_init(&sem_1,0,1);
assert(i==0);
c1=pthread_create(t1,NULL,func1,NULL);
assert(c1==0);
c2=pthread_create(t2,NULL,func2,NULL);
assert(c2==0);
c3=pthread_create(t3,NULL,func3,NULL);
assert(c3==0);
while(1){
rc=sem_post(&sem_1);
assert(rc==0);
sleep(1);
}
return 0;
}
Why would you even expect them in in an order?
Your threads do things inbetween the different waits, and according to the system scheduler, these can take different amount of time.
printf is a buffered operation that gives you exclusive access to a shared resource. So in addition to your semaphore there is a hidden lock somewhere, that also regulates the progress of your threads. Don't expect the prints to appear in order, even if the calls themselves are.
Then, for the end, using assert here is really a very bad idea. All sem_t operations can (and will) fail spuriously, so it is really bad to abort, just because such a failure.
In fact, sem_t is really a low level tool, and you should never use it without checking return values and without having a fall back strategy if such a call fails.
Of course. I can't see any order related synchronization mechanism.
One of the options to achieve the strict order is to have one semaphore per thread:
sem_t sem[3];
// ...
while(1) {
for(n = 0; n < 3; n++) {
rc=sem_post(&sem[n]);
assert(rc==0);
}
sleep(1);
}
Below Code will help to solve the problem, one semaphore for each thread used to achieve synchronization. The initial value of the semaphore does the job. used usleep to launch thread in sequence manner for needed output. The same can be done by using Mutex lock and cond variables
//declaring semaphore
sem_t sema1;
sem_t sema2;
sem_t sema3;
void* t1(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema1);
printf("Thread 1 \n");
sem_post(&sema2);
}
printf("T1 return\n");
return NULL;
}
void* t2(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema2);
printf("Thread 2 \n");
sem_post(&sema3);
}
printf("T2 return\n");
return NULL;
}
void* t3(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema3);
printf("Thread 3 \n");
sem_post(&sema1);
}
printf("T3 return \n");
return NULL;
}
int main()
{
pthread_t tid1, tid2,tid3;
sem_init(&sema1,0,1);
sem_init(&sema2,0,0);
sem_init(&sema3,0,0);
pthread_create(&tid1, NULL, t1, NULL);
usleep(100);
pthread_create(&tid2, NULL, t2, NULL);
usleep(100);
pthread_create(&tid3, NULL, t3, NULL);
pthread_join(tid3, NULL);
pthread_join(tid2, NULL);
pthread_join(tid1, NULL);
sem_destroy(&sema1);
sem_destroy(&sema2);
sem_destroy(&sema3);
return 0;
}

Mutex Threading - Code doesn't seem to Exit Properly

So I have code here which makes two kinds of threads. One kind "produces" data and the other one "consumes" it. There can only be a certain amount of data that can exist at any one time, so the Producers will pause producing once there is a certain amount of data created (ie, when sharedData = BUFFER), and the consumers will pause when sharedData = 0. There is also only so much data that can be made (amount stored in dataleft), and once all the data has been made and consumed, the program should end.
For some reason, the printf() lines I have at the end of the code don't seem to ever trigger. I can't tell if the threads are closed properly or not because of this. It feels like I've done something really stupid, but I can't see the issue.
A couple of definitions at the start:
#define NUMCONSUMERS 4
#define NUMPRODUCERS 4
#define PACKETS 10
#define tryMainlock pthread_mutex_trylock(&dataMutex)
#define openMainlock pthread_mutex_lock(&dataMutex)
#define closeMainlock pthread_mutex_unlock(&dataMutex)
#define waitMainlock pthread_cond_wait(&dataPresentCondition, &dataMutex);
#define signalMainlock pthread_cond_signal(&dataPresentCondition);
#define trydatalock pthread_mutex_trylock(&IsthereDataleft)
#define opendatalock pthread_mutex_lock(&IsthereDataleft)
#define closedatalock pthread_mutex_unlock(&IsthereDataleft)
pthread_mutex_t dataMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t dataPresentCondition = PTHREAD_COND_INITIALIZER;
pthread_mutex_t IsthereDataleft = PTHREAD_MUTEX_INITIALIZER;
int sharedData=0; //amount of data present
int BUFFER = 5;
int dataleft=PACKETS;
The Main Function:
int main(int argc, char **argv)
{
int rc;
int i;
pthread_t consumer[NUMCONSUMERS];
pthread_t producer[NUMPRODUCERS];
rc = opendatalock; //lock to determine whether there's any point waiting for data
for (i=0; i <NUMPRODUCERS; i++) { //Build up the producers
rc = pthread_create(&producer[i], NULL, Producer, (void *)i);
if (rc)
printf("Error building Producer Thread: %x\n", i);
}
for (i=0; i <NUMCONSUMERS; i++) { //Build up the consumers
rc = pthread_create(&consumer[i], NULL, Consumer, (void *)i);
if (rc)
printf("Error building Consumer Thread: %x\n", i);
}
printf("All Producers and Consumers created\n");
for (i=0; i <NUMPRODUCERS; i++) { //Join up the producers
rc = pthread_join(producer[i], NULL);
if (rc)
printf("Error: Producer %x: Failed to join\n", i);
}
rc = closedatalock; //producers finished, no data left to make
printf("datalock closed, consumers finishing...\n");
for (i=0; i <NUMCONSUMERS; i++) { //Join up the consumers
rc = pthread_join(consumer[i], NULL);
if (rc)
printf("Error: Consumer %x: Failed to join\n", i);
}
rc = pthread_mutex_destroy(&dataMutex);
rc = pthread_cond_destroy(&dataPresentCondition);
rc = pthread_mutex_destroy(&IsthereDataleft);
printf("All Threads finished. Exiting....\n");
return 0;
}
The Consumer Thread:
void *Consumer(void *threadid){
int rc;
printf("Consumer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Consumer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of main lock
if (rc)
{
printf("Consumer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //if main lock is taken, wait
if (rc) //if wait fails, exit the thread.
{
printf("Consumer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
while (sharedData == 0) //if the buffer is empty
{
rc = trydatalock;
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
sharedData--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Consumer %x: Releasing Lock\n", (int)threadid);
}
}
And the Producer Thread:
void *Producer(void *threadid){
int rc;
printf("Producer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Producer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of the lock
if (rc) //if lock is currently being used by a consumer or a producer
{
printf("Producer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //wait here until lock is released
if (rc)
{
printf("Producer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
if (!dataleft) //If there's no data left to add to the stream, close the thread
{
printf("Producer Thread %x: Completed, exiting...\n", (int)threadid);
exit(0);
}
while (sharedData >=BUFFER)
{
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
printf("Producer %x: Lock Acquired\n", (int)threadid);
sharedData++;
dataleft--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Producer %x: Releasing Lock\n", (int)threadid);
}
}
Check out this piece of code:
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
If the consumer has finished, the process(!) is terminated. You need to use pthread_exit() instead, or simply return from the thread function.
Then, there is also
../nptl/pthread_mutex_lock.c:80:
__pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
which I got a few times running the code. That could be caused by e.g. double unlock or some other invalid use. I'd start with cleaning up the weird macros, so that you have a free view on the logic of the program itself.
Also, one important advise concerning mutexes: Always document precisely which data should be protected by the mutex. The point is that it's not always clear and getting this wrong means that you accidentally access data without synchronization. In order to make this very clear, use a structure like here:
struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int data;
} synced_data = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
0
};
Actually, it's not just about the shared data that documentation is important. Consider for example IsthereDataleft: This is a mutex but it doesn't guard anything, right? Instead, it is used to signal to the started threads that there is nothing left to do, right? Documenting this not only helps others to understand your code but it makes sure that you understand yourself what the intention is. Sometimes, while trying to explain it, you will then find yourself that something doesn't make sense.
Something seems to be awry with your use of openMainlock, which expands to a pthread_mutex_lock call.
One one hand, you shouldn't expect to ever get a non-zero return value from openMainlock: pthread_mutex_lock should either return zero (lock acquired) or block, unless the mutex is not initialised or is an error-checking mutex.
Further, once the lock is acquired, if the producer is done, i.e. dataleft is zero, the thread calls exit(0), which will terminate the whole process rather than terminating the thread. pthread_exit should be used instead, or just return from the function, but note that at this point you still own the main lock, which won't be released.

pthread_join() and sleep in main

I have a program that creates two worker threads like the following:
void *Producer(void *threadarg){
while (!terminate_producer){ //do something}
printf("Producer: finalizing thread\n");
pthread_exit(NULL);
}
void *Consumer(void *threadarg){
while (!terminate_consumer){ //do something}
printf("Consumer: finalizing thread\n");
pthread_exit(NULL);
}
// Initialize array of the worker threads
void initFuncArray(long result[])
{
result[0] = (long)&Producer;
result[1] = (long)&Consumer;
}
// The main method
int main (int argc, char* argv[]){
long th_funcs[CPUS_NUM];
initFuncArray(th_funcs);
// threads data
pthread_t tid[CPUS_NUM];
thread_data prod_th_data[CPUS_NUM];
bool pt = false;
for (int i=0;i<CPUS_NUM;i++){
prod_th_data[i].thread_id = i;
pt = pthread_create(&tid[i], NULL, (void *)th_funcs[i], (void*)&prod_th_data[i]);
if (pt) return -1;
}
sleep(5);
terminate_producer = true;
pthread_join (tid[0], NULL);
**sleep(1);**
terminate_consumer = true;
pthread_join (tid[1], NULL);
// Exiting the main thread
return 0;
}
My question is about a call to sleep before terminating the consumer thread. If I do not have this call, the program terminates normally. However, if I have that sleep, the program never terminates. I see the message that the producer thread terminates, but I do not get the message from the consumer thread. What might be the problem?
Following suggestions I modified the code as follows, however, the problem now appears even without a call to sleep in-between:
typedef void (*func_type) (void *);
pthread_mutex_t terminate_producer;
pthread_mutex_t terminate_consumer;
void *Producer(void *threadarg){
while (pthread_mutex_trylock(&terminate_producer)){ //do something}
printf("Producer: finalizing thread\n");
pthread_mutex_unlock(&terminate_producer);
return NULL;
}
void *Consumer(void *threadarg){
while (pthread_mutex_trylock(&terminate_consumer))
printf("Consumer: finalizing thread\n");
pthread_mutex_unlock(&terminate_consumer);
return NULL;
}
// Initialize array of the worker threads
void initFuncArray(func_type result[])
{
result[0] = Producer;
result[1] = Consumer;
}
// The main method
int main (int argc, char* argv[]){
func_type th_funcs[CPUS_NUM];
initFuncArray(th_funcs);
// threads data
pthread_t tid[CPUS_NUM];
thread_data prod_th_data[CPUS_NUM];
// Using mutexes as termination condition
pthread_mutex_init(&terminate_producer,NULL);
pthread_mutex_init(&terminate_consumer,NULL);
pthread_mutex_lock(&terminate_producer);
pthread_mutex_lock(&terminate_consumer);
bool pt = false;
for (int i=0;i<CPUS_NUM;i++){
prod_th_data[i].thread_id = i;
pt = pthread_create(&tid[i], NULL, (void *)th_funcs[i], (void*)&prod_th_data[i]);
if (pt) return -1;
}
sleep(5);
pthread_mutex_unlock(&terminate_producer);
pthread_join (tid[0], NULL);
pthread_mutex_unlock(&terminate_consumer);
pthread_join (tid[1], NULL);
// Exiting the main thread
return 0;
}
Flag terminate_producer represents a critical section. Producers are reading its value and main thread is rewriting it at the same time. Access to this flag should be protected with some synchronization mechanism such as mutex:
inline stopProducers() {
/* GET LOCK */
terminate_producer = 1;
/* RELEASE LOCK */
}
inline unsigned char shouldProduce() {
unsigned char terminate = 0;
/* GET LOCK */
terminate = terminate_producer;
/* RELEASE LOCK */
return !terminate;
}
void *Producer(void *threadarg){
while (shouldProduce()){ /* do something */ }
printf("Producer: finalizing thread\n");
return NULL; // <-- use return instead of pthread_exit
}
and in main you would call stopProducers(); instead of rewriting the flag;
It could be due to the compiler heuristically concluding (as an optimization) that terminate_consumer is a variable which is only read in the consumer thread, so it "caches" it in a register and never reads it.
Can you change the declarations of terminate_producer and terminate_consumer to:
volatile int terminate_producer;
volatile int terminate_consumer;
.. and try again?

Resources