I have to create a solution to the readers writers problem using posix pthreads, I have condensed my code down to pseudocode mixed with C to reduce the size of the code.
The writer thread finishes fine but the reader threads never terminate/exit so the Reader join is waiting forever, and the program hangs.
I believe it is related to the wait condition pthread_cond_wait(&qElement, &mutex); in the reader function. It may be waiting for a terminated writer thread to signal. I have tried encapsulating it with if(!finished) so it only waits if the writer is still active but that still hasn't worked.
I am not sure what to do and believe it as a logic error with my pthread handling.
Would really appreciate the help.
Global variables in header file :
#define TRUE 1
#define FALSE 0
int finished = FALSE
pthread_cond_t qServiced = PTHREAD_COND_INITIALIZER;
pthread_cond_t qEmpty = PTHREAD_COND_INITIALIZER;
pthread_cond_t qElement = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int main()
{
Create 1 writer thread
Create 2 reader threads
Writer join <- Success
Reader join <- Program hangs here
void* writer()
{
int totalQueued = 0;
int tasks = 20;
while(!finished)
{
pthread_mutex_lock(&mutex);
while(isFull(q))
{
pthread_cond_wait(&qEmpty, &mutex);
}
if(totalQueued < tasks)
{
for(j = 0; j < 2; j++) //Add 2 numbers at a time
{
if(!(isFull(q)))
{
//Assume random numbers added to queue
totalQueued++;
}
}
pthread_cond_signal(&qElement);
pthread_cond_wait(&qServiced, &mutex);
}
else
{
finished = TRUE;
}
pthread_mutex_unlock(&mutex);
}
//Thread exits
}
void* reader()
{
while(!finished)
{
pthread_mutex_lock(&mutex);
while(isEmpty(q)) //If the queue is empty
{
pthread_cond_signal(&qEmpty);
pthread_cond_wait(&qElement, &mutex);
}
int n = dequeue(q);
printf("%d\n", n);
pthread_cond_signal(&qServiced); //Signal that task has been serviced
pthread_mutex_unlock(&mutex);
}
}
You having presented only a sketch of your code, I am unable to perform a complete analysis, but even the sketch shows a deficiency in your approach. When the writer makes new data available it unblocks one reader:
pthread_cond_signal(&qElement);
If both readers are waiting when the writer posts the last pieces of work (which appears likely), then one will be left waiting when the writer terminates.
The best solutions revolve around using pthread_cond_broadcast() instead of or in addition to pthread_cond_signal(). It should be fine to just substitute the latter for the former, since your readers ought to be protecting themselves against spurious wakeups anyway (and it looks like they indeed are). If you prefer, though, you can have the writer broadcast just before it terminates, or have the main thread broadcast after it joins the writer.
Additionally, I'm inclined to think that you're using a lot more CVs than you actually need. Very likely you can use just one, which will be simpler both to write and to reason about.
Related
I came across this problem as I am learning more about operating systems. In my code, I've tried making the reader having priority and it worked, so next I modified it a bit to make the writer have the priority. When I ran the code, the output was exactly the same and it seemed like the writer did not have the priority. Here is the code with comments. I am not sure what I've done wrong, since I modified a lot of the code but the output remains the same if I did not change it at all.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
/*
This program provides a possible solution for first readers writers problem using mutex and semaphore.
I have used 10 readers and 5 producers to demonstrate the solution. You can always play with these values.
*/
// Semaphore initialization for writer and reader
sem_t wrt;
sem_t rd;
// Mutex 1 blocks other readers, mutex 2 blocks other writers
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
// Value the writer is changing, we are simply multiplying this value by 2
int cnt = 2;
int numreader = 0;
int numwriter = 0;
void *writer(void *wno)
{
pthread_mutex_lock(&mutex2);
numwriter++;
if(numwriter == 1){
sem_wait(&rd);
}
pthread_mutex_unlock(&mutex2);
sem_wait(&wrt);
// Writing Section
cnt = cnt*2;
printf("Writer %d modified cnt to %d\n",(*((int *)wno)),cnt);
sem_post(&wrt);
pthread_mutex_lock(&mutex2);
numwriter--;
if(numwriter == 0){
sem_post(&rd);
}
pthread_mutex_unlock(&mutex2);
}
void *reader(void *rno)
{
sem_wait(&rd);
pthread_mutex_lock(&mutex1);
numreader++;
if(numreader == 1){
sem_wait(&wrt);
}
pthread_mutex_unlock(&mutex1);
sem_post(&rd);
// Reading Section
printf("Reader %d: read cnt as %d\n",*((int *)rno),cnt);
pthread_mutex_lock(&mutex1);
numreader--;
if(numreader == 0){
sem_post(&wrt);
}
pthread_mutex_unlock(&mutex1);
}
int main()
{
pthread_t read[10],write[5];
pthread_mutex_init(&mutex1, NULL);
pthread_mutex_init(&mutex2, NULL);
sem_init(&wrt,0,1);
sem_init(&rd,0,1);
int a[10] = {1,2,3,4,5,6,7,8,9,10}; //Just used for numbering the writer and reader
for(int i = 0; i < 5; i++) {
pthread_create(&write[i], NULL, (void *)writer, (void *)&a[i]);
}
for(int i = 0; i < 10; i++) {
pthread_create(&read[i], NULL, (void *)reader, (void *)&a[i]);
}
for(int i = 0; i < 5; i++) {
pthread_join(write[i], NULL);
}
for(int i = 0; i < 10; i++) {
pthread_join(read[i], NULL);
}
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
sem_destroy(&wrt);
sem_destroy(&rd);
return 0;
}
Output (for both is the same. I think if writer had priority it will change first, then will be read):
Alternative Semantics
Much of what you want to do can probably be accomplished with less overhead. For example, in the classic reader-writer problem, readers shouldn’t need to block other readers.
You might be able to replace the reader-writer pattern with a publisher-consumer pattern that manages pointers to blocks of data with acquire-consume memory ordering. You only need locking at all if one thread needs to update the same block of memory after it was originally written.
POSIX and Linux have an implementation of reader-writer locks in the system library, which were designed to avoid starvation. This is most likely the high-level construct you want.
If you still want to implement your own, one implementation would use a count of current readers, a count of pending writers and a flag that indicates whether a write is in progress. It packs all these values into an atomic bitfield that it updates with a compare-and-swap.
Reader threads would retrieve the value, check whether there are any starving writers waiting, and if not, increment the count of readers. If there are writers, it backs off (perhaps spinning and yielding the CPU, perhaps sleeping on a condition variable). If there is a write in progress, it waits for that to complete. If it sees only other reads in progress, it goes ahead.
Writer threads would check if there are any reads or writes in progress. If so, they increment the count of waiting writers, and wait. If not, they set the write-in-progress bit and proceed.
Packing all these fields into the same atomic bitfield guarantees that no thread will think it’s safe to use the buffer while another thread thinks it’s safe to write: if two threads try to update the state at the same time, one will always fail.
If You Stick With Semaphores
You can still have reader threads check sem_getvalue() on the writer semaphore, and back off if they see any starved writers are waiting. One method would be to wait on a condition variable that threads signal when they are done with the buffer. A reader that sees that it holds the mutex while writers are waiting can try to wake up one writer thread and go back to sleep, and a reader that sees only other readers are waiting can wake up a reader, which will wake up the next reader, and so on.
I have problem with readers-writers problem. I want to write writers favor solution using mutex. So far i have written this
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <memory.h>
#include <stdbool.h>
#include <stdint.h>
#include<unistd.h>
int NO_READERS;
int NO_WRITERS;
int NO_READERS_READING = 0; // How many readers need shared resources
int NO_WRITERS_WRITING = 0; // How many writers need shared resources
pthread_mutex_t resourceMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t tryResourceMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t readerMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t writerMutex = PTHREAD_MUTEX_INITIALIZER;
void *readerJob(void *arg) {
int *id = (int*)arg;
while (1) {
pthread_mutex_lock(&tryResourceMutex); // Indicate reader is trying to enter
pthread_mutex_lock(&readerMutex);
NO_READERS_READING++; // Indicate that you are needing the shared resource (one more reader)
if (NO_READERS_READING == 1) {
pthread_mutex_lock(&resourceMutex);
}
pthread_mutex_unlock(&readerMutex);
pthread_mutex_unlock(&tryResourceMutex);
printf("READER ID %d WALKED IN \n",*id);
printf("ReaderQ: %d , WriterQ: %d [in: R:%d W:%d]\n",
NO_READERS - NO_READERS_READING,
NO_WRITERS - NO_WRITERS_WRITING,
NO_READERS_READING,
NO_WRITERS_WRITING);
sleep(1);
pthread_mutex_lock(&readerMutex);
NO_READERS_READING--;
if (NO_READERS_READING == 0) { // Check if you are the last reader
pthread_mutex_unlock(&resourceMutex);
}
pthread_mutex_unlock(&readerMutex);
}
return 0;
}
void *writerJob(void *arg) {
int *id = (int*)arg;
while (1) {
pthread_mutex_lock(&writerMutex);
NO_WRITERS_WRITING++;
if (NO_WRITERS_WRITING == 1) {
pthread_mutex_lock(&tryResourceMutex); // If there are no other writers lock the readers out
}
pthread_mutex_unlock(&writerMutex);
pthread_mutex_lock(&resourceMutex);
printf("WRITER ID %d WALKED IN \n",*id);
printf("ReaderQ: %d , WriterQ: %d [in: R:%d W:%d]\n",
NO_READERS - NO_READERS_READING,
NO_WRITERS - NO_WRITERS_WRITING,
NO_READERS_READING,
NO_WRITERS_WRITING);
sleep(1);
pthread_mutex_unlock(&resourceMutex);
pthread_mutex_lock(&writerMutex);
NO_WRITERS_WRITING--;
if (NO_WRITERS_WRITING == 0) {
pthread_mutex_unlock(&tryResourceMutex); // If there are no writers left unlock the readers
}
pthread_mutex_unlock(&writerMutex);
}
return 0;
}
int main(int argc, char *argv[]) {
NO_READERS = atoi(argv[1]);
NO_WRITERS = atoi(argv[2]);
// Initialize arrays of threads IDs
pthread_t *readersThreadsIds = malloc(NO_READERS * sizeof(pthread_t));
pthread_t *writersThreadsIds = malloc(NO_READERS * sizeof(pthread_t));
// Initialize shared memory (array) with random numbers
// Create readers threads
for (int i = 0; i < NO_READERS; ++i) {
int* id = (int*)(malloc(sizeof(int)));
*id = i;
pthread_create(&readersThreadsIds[i], NULL, readerJob,(void*)id);
}
// Create writers threads
for (int i = 0; i < NO_WRITERS; ++i) {
int* id = (int*)(malloc(sizeof(int)));
*id = i;
pthread_create(&writersThreadsIds[i], NULL, writerJob, (void*)id);
}
// Wait for readers to finish
for (int i = 0; i < NO_READERS; ++i) {
pthread_join(readersThreadsIds[i], NULL);
}
// Wait for writers to finish
for (int i = 0; i < NO_WRITERS; ++i) {
pthread_join(writersThreadsIds[i], NULL);
}
free(readersThreadsIds);
free(writersThreadsIds);
pthread_mutex_destroy(&resourceMutex);
pthread_mutex_destroy(&tryResourceMutex);
pthread_mutex_destroy(&readerMutex);
pthread_mutex_destroy(&writerMutex);
return 0;
}
And I'm not sure if this should be working like this. Can anyone check this for me? I want to have information about which reader or writer is going in or out. It seems like it stuck in some point but I don't know why.
It seems to do what you want, that is give preference to the writers. Because your threads loop acquiring and releasing the lock; if you have more than one writer, the writers will take turns passing it between themselves and starve the readers. That is, every time one releases the resourceMutex, there is another writer waiting on it, so NO_WRITERS_WRITING will never hit zero.
To see it operating as intended, add a delay at the top of the while loop of each thread:
usleep((rand() % 10000) * 10000);
That will permit the readers to periodically get access, whenever all the writers are in the usleep().
At the begining all readers are coming in,
By "coming in", I take you to mean executing the printf() calls in the readerJob loop. It's not surprising that the readers all come in first, because you start them first, and in the likely event that the first reader thread to attempt to lock tryResourceMutex does so before any writer thread does, it will then lock resourceMutex(), too, preventing any writer from "coming in". But that does not prevent writers from incrementing NO_WRITERS_WRITING. And it also does not preventing one of them from locking tryResourceMutex and holding it locked.
The sleep() call in the reader will then (probably) cause resourceMutex to be held continuously long enough that all the readers come in before any of the writers do, since each writer needs to acquire resourceMutex to come in.
then also writers which shouldn't be possible at the same time.
I don't see that in my tests. But I do see what I already described: the writer count increases from zero, even though they are prevented from coming in while any readers are inside. In effect, the name of your variable NO_WRITERS_WRITING is inconsistent with your actual usage -- indicates how many writers are writing or waiting to write.
When the readers leave they are blocked from reentering right away because one of the writers holds tryResourceMutex. Eventually, then, the last reader will exit and release the resourceMutex. This will allow the writers to proceed, one at a time, but with the sleep() call positioned where it is in the writer loop, it is extremely unlikely that the number of writers will ever fall to zero to allow any of the readers to re-enter. If it did, however, then very likely the same cycle would repeat: all of the readers would enter, once, while all the writers queue up.
Then all readers are gone but there are more than one writer at the same time in library.
Again, no. Only one writer is inside at a time, but the others are queued most of the time, so NO_WRITERS_WRITING will almost always be equal to NO_WRITERS.
Bottom line, then: you have confused yourself. You are using variable NO_WRITERS_WRITING primarily to represent the number of writers that are ready to write, but your messaging uses it as if it were the number actually writing. The same does not apply to NO_READERS_READING because once a thread acquires the mutex needed to modify that variable, nothing else prevents it from proceeding on into the room.
One more thing: to make the simulation interesting -- i.e. to keep the writers from taking permanent control -- you should implement a delay, preferably a random one, after each thread leaves the room, before it tries to reenter. And the delay for writers should probably be substantially longer than the delay for readers.
I'm currently learning about concurrency at my University. In this context I have to implement the reader/writer problem in C, and I think I'm on the right track.
My thought on the problem is, that we need two locks rd_lock and wr_lock. When a writer thread wants to change our global variable, it tries to grab both locks, writes to the global and unlocks. When a reader wants to read the global, it checks if wr_lock is currently locked, and then reads the value, however one of the reader threads should grab the rd_lock, but the other readers should not care if rd_lock is locked.
I am not allowed to use the implementation already in the pthread library.
typedef struct counter_st {
int value;
} counter_t;
counter_t * counter;
pthread_t * threads;
int readers_tnum;
int writers_tnum;
pthread_mutex_t rd_lock;
pthread_mutex_t wr_lock;
void * reader_thread() {
while(true) {
pthread_mutex_lock(&rd_lock);
pthread_mutex_trylock(&wr_lock);
int value = counter->value;
printf("%d\n", value);
pthread_mutex_unlock(&rd_lock);
}
}
void * writer_thread() {
while(true) {
pthread_mutex_lock(&wr_lock);
pthread_mutex_lock(&rd_lock);
// TODO: increment value of counter->value here.
counter->value += 1;
pthread_mutex_unlock(&rd_lock);
pthread_mutex_unlock(&wr_lock);
}
}
int main(int argc, char **args) {
readers_tnum = atoi(args[1]);
writers_tnum = atoi(args[2]);
pthread_mutex_init(&rd_lock, 0);
pthread_mutex_init(&wr_lock, 0);
// Initialize our global variable
counter = malloc(sizeof(counter_t));
counter->value = 0;
pthread_t * threads = malloc((readers_tnum + writers_tnum) * sizeof(pthread_t));
int started_threads = 0;
// Spawn reader threads
for(int i = 0; i < readers_tnum; i++) {
int code = pthread_create(&threads[started_threads], NULL, reader_thread, NULL);
if (code != 0) {
printf("Could not spawn a thread.");
exit(-1);
} else {
started_threads++;
}
}
// Spawn writer threads
for(int i = 0; i < writers_tnum; i++) {
int code = pthread_create(&threads[started_threads], NULL, writer_thread, NULL);
if (code != 0) {
printf("Could not spawn a thread.");
exit(-1);
} else {
started_threads++;
}
}
}
Currently it just prints a lot of zeroes, when run with 1 reader and 1 writer, which means, that it never actually executes the code in the writer thread. I know that this is not going to work as intended with multiple readers, however I don't understand what is wrong, when running it with one of each.
Don't think of the locks as "reader lock" and "writer lock".
Because you need to allow multiple concurrent readers, readers cannot hold a mutex. (If they do, they are serialized; only one can hold a mutex at the same time.) They can take one for a short duration (before they begin the access, and after they end the access), to update state, but that's it.
Split the timeline for having a rwlock into three parts: "grab rwlock", "do work", "release rwlock".
For example, you could use one mutex, one condition variable, and a counter. The counter holds the number of active readers. The condition variable is signaled on by the last reader, and by writers just before they release the mutex, to wake up a waiting writer. The mutex protects both, and is held by writers for the whole duration of their write operation.
So, in pseudocode, you might have
Function rwlock_rdlock:
Take mutex
Increment counter
Release mutex
End Function
Function rwlock_rdunlock:
Take mutex
Decrement counter
If counter == 0, Then:
Signal_on cond
End If
Release mutex
End Function
Function rwlock_wrlock:
Take mutex
While counter > 0:
Wait_on cond
End Function
Function rwlock_unlock:
Signal_on cond
Release mutex
End Function
Remember that whenever you wait on a condition variable, the mutex is atomically released for the duration of the wait, and automatically grabbed when the thread wakes up. So, for waiting on a condition variable, a thread will have the mutex both before and after the wait, but not during the wait itself.
Now, the above approach is not the only one you might implement.
In particular, you might note that in the above scheme, there is a different "unlock" operation you must use, depending on whether you took a read or a write lock on the rwlock. In POSIX pthread_rwlock_t implementation, there is just one pthread_rwlock_unlock().
Whatever scheme you design, it is important to examine it whether it works right in all situations: a lone read-locker, a lone-write-locker, several read-lockers, several-write-lockers, a lone write-locker and one read-locker, a lone write-locker and several read-lockers, several write-lockers and a lone read-locker, and several read- and write-lockers.
For example, let's consider the case when there are several active readers, and a writer wants to write-lock the rwlock.
The writer grabs the mutex. It then notices that the counter is nonzero, so it starts waiting on the condition variable. When the last reader -- note how the order of the readers exiting does not matter, since a simple counter is used! -- unlocks its readlock on the rwlock, it signals on the condition variable, which wakes up the writer. The writer then grabs the mutex, sees the counter is zero, and proceeds to do its work. During that time, the mutex is held by the writer, so all new readers will block, until the writer releases the mutex. Because the writer will also signal on the condition variable when it releases the mutex, it is a race between other waiting writers and waiting readers, who gets to go next.
I am working on the dining philosophers problem, where n philosophers take turns thinking and eating. I would like to have a version of this where the philosophers will eat in the order of their id: 0,1,2,3,4...,but my threads keep getting blocked. My threads start by calling PhilosopherThread().
void putDownChopsticks(int threadIndex){
//finished eating
pindex++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void pickUpChopsticks(int threadIndex){
pthread_mutex_lock(&lock);
while(pindex != threadIndex){
pthread_cond_wait(&cond, &lock);
}
//lets go eat
}
void eating(){
//put thread to sleep
}
void thinking(){
//put thread to sleep
}
void* PhilosopherThread(void *x){
int *index = x;
thinking(); //just puts thread to sleep to simulate thinking
pickUpChopsticks(*index);
eating(); //just puts thread to sleep to simulate eating
putDownChopsticks(*index);
return NULL;
}
I'm having a bit of trouble trying to get the philosophers in order. I can only get the first 2 threads to eat before the threads get blocked.
Edit: as far as i know im doing this right. I first lock the mutex, then I check if pindex is the current thread id, if its not the thread will wait until pindex does equal the id. Then the thread can go eat and once where done, we incread pindex, signal that the thread is done, and unlock the mutex.
This code sometimes works and sometimes does not. First, since you did not provide a complete program, here are the missing bits I used for testing purposes:
#include <stdlib.h>
#include <pthread.h>
static pthread_cond_t cond;
static pthread_mutex_t lock;
static pindex;
/* ... your code ... */
int main () {
int id[5], i;
pthread_t tid[5];
for (i = 0; i < 5; ++i) {
id[i] = i;
pthread_create(tid+i, 0, PhilosopherThread, id+i);
}
for (i = 0; i < 5; ++i) pthread_join(tid[i], 0);
exit(0);
}
The critical piece to notice is how you wake up the next philosopher:
pthread_cond_signal(&cond);
This call will only wake up one thread. But, which thread is at the discretion of the OS. Therefore, if it does not happen to wake up the philosopher that is supposed to wake up, no other philosopher is woken up.
A simple fix would be to wake up all waiting threads instead of just one. The philosophers that don't match will go back to waiting, and the one that is supposed to go next will go.
pthread_cond_broadcast(&cond);
However, since each thread knows which philosopher should wake up, you could change your solution to allow that to happen. One way could be to implement a separate condition variable per philosopher, and use pthread_cond_signal() on the next philosopher's condition variable.
I am trying to write a code that does not block main() when pthread_join() is called:
i.e. basically trying to implement my previous question mentioned below:
https://stackoverflow.com/questions/24509500/pthread-join-and-main-blocking-multithreading
And the corresponding explanation at:
pthreads - Join on group of threads, wait for one to exit
As per suggested answer:
You'd need to create your own version of it - e.g. an array of flags (one flag per thread) protected by a mutex and a condition variable; where just before "pthread_exit()" each thread acquires the mutex, sets its flag, then does "pthread_cond_signal()". The main thread waits for the signal, then checks the array of flags to determine which thread/s to join (there may be more than one thread to join by then).
I have tried as below:
My status array which keeps a track of which threads have finished:
typedef struct {
int Finish_Status[THREAD_NUM];
int signalled;
pthread_mutex_t mutex;
pthread_cond_t FINISHED;
}THREAD_FINISH_STATE;
The thread routine, it sets the corresponding array element when the thread finishes and also signals the condition variable:
void* THREAD_ROUTINE(void* arg)
{
THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
printf("Thread created with id %d\n",temp->id);
waitFor(5);
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
{
pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
printf("Signal that thread %d finished\n",temp->id);
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
pthread_exit((void*)(temp->id));
}
I am not able to write the corresponding parts pthread_join() and pthread_cond_wait() functions. There are a few things which I am not able to implement.
1) How to write corresponding part pthread_cond_wait() in my main()?
2) I am trying to write it as:
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
while((ThreadFinishStatus.signalled != TRUE){
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled==FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
But it does not enter the while loop.
3) How to use pthread_join() so that I can get the return value stored in my arg[i].returnStatus
i.e. where to put below statement in my main:
`pthread_join(T[i],&(arg[i].returnStatus));`
COMPLETE CODE
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#define THREAD_NUM 5
#define FALSE 0
#define TRUE 1
void waitFor (unsigned int secs) {
time_t retTime;
retTime = time(0) + secs; // Get finishing time.
while (time(0) < retTime); // Loop until it arrives.
}
typedef struct {
int Finish_Status[THREAD_NUM];
int signalled;
pthread_mutex_t mutex;
pthread_cond_t FINISHED;
}THREAD_FINISH_STATE;
typedef struct {
int id;
void* returnStatus;
}THREAD_ARGUMENT;
THREAD_FINISH_STATE ThreadFinishStatus;
void initializeState(THREAD_FINISH_STATE* state)
{
int i=0;
state->signalled=FALSE;
for(i=0;i<THREAD_NUM;i++)
{
state->Finish_Status[i]=FALSE;
}
pthread_mutex_init(&(state->mutex),NULL);
pthread_cond_init(&(state->FINISHED),NULL);
}
void destroyState(THREAD_FINISH_STATE* state)
{
int i=0;
for(i=0;i<THREAD_NUM;i++)
{
state->Finish_Status[i]=FALSE;
}
pthread_mutex_destroy(&(state->mutex));
pthread_cond_destroy(&(state->FINISHED));
}
void* THREAD_ROUTINE(void* arg)
{
THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
printf("Thread created with id %d\n",temp->id);
waitFor(5);
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
{
pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
printf("Signal that thread %d finished\n",temp->id);
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
pthread_exit((void*)(temp->id));
}
int main()
{
THREAD_ARGUMENT arg[THREAD_NUM];
pthread_t T[THREAD_NUM];
int i=0;
initializeState(&ThreadFinishStatus);
for(i=0;i<THREAD_NUM;i++)
{
arg[i].id=i;
}
for(i=0;i<THREAD_NUM;i++)
{
pthread_create(&T[i],NULL,THREAD_ROUTINE,(void*)&arg[i]);
}
/*
Join only if signal received
*/
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
//Wait
while((ThreadFinishStatus.signalled != TRUE){
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled==FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
destroyState(&ThreadFinishStatus);
return 0;
}
Here is an example of a program that uses a counting semaphore to watch as threads finish, find out which thread it was, and review some result data from that thread. This program is efficient with locks - waiters are not spuriously woken up (notice how the threads only post to the semaphore after they've released the mutex protecting shared state).
This design allows the main program to process the result from some thread's computation immediately after the thread completes, and does not require the main wait for all threads to complete. This would be especially helpful if the running time of each thread varied by a significant amount.
Most importantly, this program does not deadlock nor race.
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <queue>
void* ThreadEntry(void* args );
typedef struct {
int threadId;
pthread_t thread;
int threadResult;
} ThreadState;
sem_t completionSema;
pthread_mutex_t resultMutex;
std::queue<int> threadCompletions;
ThreadState* threadInfos;
int main() {
int numThreads = 10;
int* threadResults;
void* threadResult;
int doneThreadId;
sem_init( &completionSema, 0, 0 );
pthread_mutex_init( &resultMutex, 0 );
threadInfos = new ThreadState[numThreads];
for ( int i = 0; i < numThreads; i++ ) {
threadInfos[i].threadId = i;
pthread_create( &threadInfos[i].thread, NULL, &ThreadEntry, &threadInfos[i].threadId );
}
for ( int i = 0; i < numThreads; i++ ) {
// Wait for any one thread to complete; ie, wait for someone
// to queue to the threadCompletions queue.
sem_wait( &completionSema );
// Find out what was queued; queue is accessed from multiple threads,
// so protect with a vanilla mutex.
pthread_mutex_lock(&resultMutex);
doneThreadId = threadCompletions.front();
threadCompletions.pop();
pthread_mutex_unlock(&resultMutex);
// Announce which thread ID we saw finish
printf(
"Main saw TID %d finish\n\tThe thread's result was %d\n",
doneThreadId,
threadInfos[doneThreadId].threadResult
);
// pthread_join to clean up the thread.
pthread_join( threadInfos[doneThreadId].thread, &threadResult );
}
delete threadInfos;
pthread_mutex_destroy( &resultMutex );
sem_destroy( &completionSema );
}
void* ThreadEntry(void* args ) {
int threadId = *((int*)args);
printf("hello from thread %d\n", threadId );
// This can safely be accessed since each thread has its own space
// and array derefs are thread safe.
threadInfos[threadId].threadResult = rand() % 1000;
pthread_mutex_lock( &resultMutex );
threadCompletions.push( threadId );
pthread_mutex_unlock( &resultMutex );
sem_post( &completionSema );
return 0;
}
Pthread conditions don't have "memory"; pthread_cond_wait doesn't return if pthread_cond_signal is called before pthread_cond_wait, which is why it's important to check the predicate before calling pthread_cond_wait, and not call it if it's true. But that means the action, in this case "check which thread to join" should only depend on the predicate, not on whether pthread_cond_wait is called.
Also, you might want to make the while loop actually wait for all the threads to terminate, which you aren't doing now.
(Also, I think the other answer about "signalled==FALSE" being harmless is wrong, it's not harmless, because there's a pthread_cond_wait, and when that returns, signalled would have changed to true.)
So if I wanted to write a program that waited for all threads to terminate this way, it would look more like
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
// AllThreadsFinished would check that all of Finish_Status[] is true
// or something, or simpler, count the number of joins completed
while (!AllThreadsFinished()) {
// Wait, keeping in mind that the condition might already have been
// signalled, in which case it's too late to call pthread_cond_wait,
// but also keeping in mind that pthread_cond_wait can return spuriously,
// thus using a while loop
while (!ThreadFinishStatus.signalled) {
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
}
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled=FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
Your code is racy.
Suppose you start a thread and it finishes before you grab the mutex in main(). Your while loop will never run because signalled was already set to TRUE by the exiting thread.
I will echo #antiduh's suggestion to use a semaphore that counts the number of dead-but-not-joined threads. You then loop up to the number of threads spawned waiting on the semaphore. I'd point out that the POSIX sem_t is not like a pthread_mutex in that sem_wait can return EINTR.
Your code appears fine. You have one minor buglet:
ThreadFinishStatus.signalled==FALSE; //Reset signalled
This does nothing. It tests whether signalled is FALSE and throws away the result. That's harmless though since there's nothing you need to do. (You never want to set signalled to FALSE because that loses the fact that it was signalled. There is never any reason to unsignal it -- if a thread finished, then it's finished forever.)
Not entering the while loop means signalled is TRUE. That means the thread already set it, in which case there is no need to enter the loop because there's nothing to wait for. So that's fine.
Also:
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
There's no need to test the thing you just set. It's not like the set can fail.
FWIW, I would suggest re-architecting. If the existing functions like pthread_join don't do exactly what you want, just don't use them. If you're going to have structures that track what work is done, then totally separate that from thread termination. Since you will already know what work is done, what different does it make when and how threads terminate? Don't think of this as "I need a special way to know when a thread terminates" and instead think of this "I need to know what work is done so I can do other things".