0

Basically the main thread creates threads 1 2 3 4. And 1 2 3 have to wait for 4 to end and main waits for threads 1 2 3. The code is as follows:

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
pthread_t id[4];
void *func1(void *arg)
{
    printf("I am the %ith thread\n",(int)arg);
    pthread_join(id[3],NULL);
    printf("End of %ith thread\n",(int)arg);
    pthread_exit(NULL);
}
void *func2(void *arg)
{
    printf("I am the 4th thread\n");
    sleep(5);
    printf("End of 4th thread\n");
    pthread_exit(NULL);
}
int main()
{
    printf("Start of main thread\n");
    pthread_create(&id[3],NULL,func2,NULL);
    for(int i=0;i<3;i++)
    {
        pthread_create(&id[i],NULL,func1,(void *)i);
    }
    for(int i=0;i<3;i++)
    {
        pthread_join(id[i],NULL);
    }
    printf("End of main\n");
    return 0;  
}

When running I get something like this:

Start of main thread
I am the 0th thread
I am the 4th thread
I am the 2th thread
I am the 1th thread
End of 4th thread
End of 0th thread

In theory threads 1 2 3 should wait for 4 and then finish up themselves, but at every try only one thread finishes after 4 and then the entire execution is blocked indefinitely. I tried making sure that the 4th thread always starts first with a pthread_attr_t and setting the sched-priority of the 4th high and that did not work unfortunately. I tried looking up some details about pthread_join and if joining multiple threads to one threads is not safe or not allowed but I didn't find anything to suggest that.

user16217248
  • 3,119
  • 19
  • 19
  • 37
  • If all threads have to wait for `4`, why is `4` even a thread? Perhaps you should run `4` as a normal function before you run threads `1`, `2` and `3`? – Some programmer dude Apr 08 '23 at 18:40
  • After you joined `id[3]` in `func1()` first time it no longer exists. Subsequent calls to `join(id[3])` will fail. – dimich Apr 08 '23 at 18:42
  • @dimich ah i see thank you very much, in this case either i must have misunderstood the task or the teacher made some mistake while describing the task in any case thank you very much. – Abdellah Badaoui Apr 08 '23 at 19:38
  • 1
    @Someprogrammerdude tbh the task seemed banal especially after how advanced we got in this OS course but we as students unfortunately are graded upon our answers to these banal tasks, but i had the exact same thought because in the exercise we were basically given a diagram and this diagram looked very unorthodox and this was the only way i could make sense of it, i'll have to ask my teacher about it. – Abdellah Badaoui Apr 08 '23 at 19:42

1 Answers1

1

From pthread_join() manual page:

If multiple threads simultaneously try to join with the same thread, the results are undefined.

If you need to wait for thread termination in multiple threads, create corresponding flag wrapped to condition variable. Broadcast condition variable either in terminating thread right before exit or after joining the thread in one of another threads.

Additional remarks:

  • Always check return values from system functions.
  • pthread_exit(NULL) is redundant at the end of thread function. Just return NULL.
  • Casting from int to void* and back may overflow, compiler don't like that. We could use intptr_t instead of int but there is no conversion specifier for intptr_t in printf(), so we should cast anyway. We can use intermediate casting to intptr_t to make compiler happy.

The program may be like this:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

static pthread_t id[4];

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static int terminated = 0;

static void *func1(void *arg)
{
    printf("i am the %ith thread\n",(int)(intptr_t)arg);

    // Wait until 4th thread termination flag is set
    pthread_mutex_lock(&mtx);
    while (!terminated) {
        pthread_cond_wait(&cond, &mtx);
    }
    pthread_mutex_unlock(&mtx);

    printf("end of %ith thread\n",(int)(intptr_t)arg);
    return NULL;
}

static void *func2(void *)
{
    printf("i am the 4th thread\n");
    sleep(5);
    printf("end of 4th thread\n");

    // Set termination flag and broadcast state change
    pthread_mutex_lock(&mtx);
    terminated = 1;
    pthread_mutex_unlock(&mtx);
    pthread_cond_broadcast(&cond);

    return NULL;
}

int main()
{
    printf("start of main thread\n");
    int ret;

    ret = pthread_create(&id[3],NULL,func2,NULL);
    if (ret) {
        fprintf(stderr, "pthread_create(id[3]): %s\n", strerror(ret));
        return 1;
    }

    for(int i=0;i<3;i++)
    {
        ret = pthread_create(&id[i],NULL,func1,(void *)(intptr_t)i);
        if (ret) {
            fprintf(stderr, "pthread_create(id[%i]): %s\n", i, strerror(ret));
            return 1;
        }
    }

    // Wait for all 4 threads
    for(int i=0;i<4;i++)
    {
        int ret = pthread_join(id[i],NULL);
        if (ret != 0) {
            fprintf(stderr, "pthread_join(id[%i]): %s\n", i, strerror(ret));
        }
    }

    printf("end of main\n");
    return 0;  
}

UPD: There is simpler way: wrap pthread_join() call into critical section guarded with mutex:

static pthread_t id[4];

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static int terminated = 0;

static void *func1(void *arg)
{
    printf("i am the %ith thread\n",(int)(intptr_t)arg);

    // Wait until 4th thread termination flag is set
    pthread_mutex_lock(&mtx);
    if (!terminated) {
        int ret = pthread_join(id[3],NULL);
        if (ret != 0) {
            fprintf(stderr, "pthread_join(id[3]): %s\n", strerror(ret));
        }
        terminated = 1;
    }
    pthread_mutex_unlock(&mtx);

    printf("end of %ith thread\n",(int)(intptr_t)arg);
    return NULL;
}

static void *func2(void *)
{
    printf("i am the 4th thread\n");
    sleep(5);
    printf("end of 4th thread\n");

    return NULL;
}

In this case you don't need to join 4th thread in main():

    for(int i=0;i<3;i++) {
        int ret = pthread_join(id[i],NULL);
    ...
dimich
  • 1,305
  • 1
  • 5
  • 7