For some reason I thought that calling pthread_exit(NULL)
at the end of a main function would guarantee that all running threads (at least created in the main function) would finish running before main
could exit. However when I run this code below without calling the two pthread_join
functions (at the end of main
) explicitly I get a segmentation fault, which seems to happen because the main
function has been exited before the two threads finish their job, and therefore the char buffer is not available anymore. However when I include these two pthread_join
function calls at the end of main
it runs as it should. To guarantee that main
will not exit before all running threads have finished, is it necessary to call pthread_join
explicitly for all threads initialized directly in main
?
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#define NUM_CHAR 1024
#define BUFFER_SIZE 8
typedef struct {
pthread_mutex_t mutex;
sem_t full;
sem_t empty;
char* buffer;
} Context;
void *Reader(void* arg) {
Context* context = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(&context->full);
pthread_mutex_lock(&(context->mutex));
char c = context->buffer[i % BUFFER_SIZE];
pthread_mutex_unlock(&(context->mutex));
sem_post(&context->empty);
printf("%c", c);
}
printf("\n");
return NULL;
}
void *Writer(void* arg) {
Context* context = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(&context->empty);
pthread_mutex_lock(&(context->mutex));
context->buffer[i % BUFFER_SIZE] = 'a' + (rand() % 26);
float ranFloat = (float) rand() / RAND_MAX;
if (ranFloat < 0.5) sleep(0.2);
pthread_mutex_unlock(&(context->mutex));
sem_post(&context->full);
}
return NULL;
}
int main() {
char buffer[BUFFER_SIZE];
pthread_t reader, writer;
Context context;
srand(time(NULL));
int status = 0;
status = pthread_mutex_init(&context.mutex, NULL);
status = sem_init(&context.full,0,0);
status = sem_init(&context.empty,0, BUFFER_SIZE);
context.buffer = buffer;
status = pthread_create(&reader, NULL, Reader, &context);
status = pthread_create(&writer, NULL, Writer, &context);
pthread_join(reader,NULL); // This line seems to be necessary
pthread_join(writer,NULL); // This line seems to be necessary
pthread_exit(NULL);
return 0;
}
If that is the case, how could I handle the case where plenty of identical threads (like in the code below) would be created using the same thread identifier? In that case, how can I make sure that all the threads will have finished before main
exits? Do I really have to keep an array of NUM_STUDENTS pthread_t
identifiers to be able to do this? I guess I could do this by letting the Student threads signal a semaphore and then let the main
function wait on that semaphore, but is there really no easier way to do this?
int main()
{
pthread_t thread;
for (int i = 0; i < NUM_STUDENTS; i++)
pthread_create(&thread,NULL,Student,NULL); // Threads
// Make sure that all student threads have finished
exit(0);
}
The POSIX thread libraries are a standards based thread API for C/C++. It allows one to spawn a new concurrent process flow. It is most effective on multi-processor or multi-core systems where the process flow can be scheduled to run on another processor thus gaining speed through parallel or distributed processing.
RETURN VALUE The pthread_exit() function cannot return to its caller.
The pthread_exit() function terminates the calling thread and makes the value value_ptr available to any successful join with the terminating thread. Any cancellation cleanup handlers that have been pushed and not yet popped are popped in the reverse order that they were pushed and then executed.
On return from a successful pthread_join() call with a non-NULL value_ptr argument, the value passed to pthread_exit() by the terminating thread shall be made available in the location referenced by value_ptr. When a pthread_join() returns successfully, the target thread has been terminated.
pthread_exit()
is a function called by a thread to terminate its own execution. For the situation you've given it is not to be called from your main program thread.
As you have figured out, pthread_join()
is the correct means to wait for the completion of a joinable thread from main()
.
Also as you've figured out, you need to maintain the value returned from pthread_create()
to pass to pthread_join()
.
What this means is that you cannot use the same pthread_t
variable for all the threads you create if you intend to use pthread_join()
.
Rather, build an array of pthread_t
so that you have a copy of each thread's ID.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With