46

I intend to fire 2 threads in the main thread, and the main thread should wait till all the 2 child threads finish, this is how I do it.

void *routine(void *arg)
{
    sleep(3);
}

int main()
{
    for (int i = 0; i < 2; i++) {
        pthread_t tid;
        pthread_create(&tid, NULL, routine, NULL);
        pthread_join(&tid, NULL);  //This function will block main thread, right?
    }
}

In the above code, pthread_join indeed makes main thread wait for the child threads, but the problem is, the second thread won't be created untill the first one finishes. This is not what I want.

What I want is, the 2 threads get created immediatly in the main thread, and then main thread waits for them to finish. Seems like pthread_join cannot do the trick, can it?

I thought, maybe via a semaphore I can do the job, but any other way?

Alcott
  • 17,905
  • 32
  • 116
  • 173

4 Answers4

81
int main()
{
    pthread_t tid[2];
    for (int i = 0; i < 2; i++) {
        pthread_create(&tid[i], NULL, routine, NULL);
    }
    for (int i = 0; i < 2; i++)
       pthread_join(tid[i], NULL);
    return 0;
}
perreal
  • 94,503
  • 21
  • 155
  • 181
  • how do we do that on windows? @perreal – Ahmed Can Unbay Oct 07 '17 at 14:47
  • I know that this goes way back but I want to ask something. Threads might fire right when the `pthread_create` returns, wouldn't this cause any problems I the threads are created and terminated before they're joined? – Tortellini Teusday Sep 21 '20 at 13:39
  • I don't fully understand your concern, but please read the doc for the join function. It waits for the thread if the thread is in execution or just returns. – perreal Sep 21 '20 at 13:44
  • From what I understand this code may not work. The [pthread_join](https://www.man7.org/linux/man-pages/man3/pthread_join.3.html) function would suspend the "main thread" until thread A finishes its execution, the problem is that thread B may have finished in that time, so the next call to [pthread_join](https://www.man7.org/linux/man-pages/man3/pthread_join.3.html) would generate undefined behavior. – MrDave1999 Jan 18 '21 at 16:00
  • 1
    "The pthread_join() function waits for the thread specified by thread to terminate. If that thread has already terminated, then pthread_join() returns immediately." – perreal Jan 18 '21 at 16:32
  • Sure enough, you said practically what pthread_join does. Quoted from this [page](https://www.man7.org/linux/man-pages/man3/pthread_join.3.html): *"If multiple threads simultaneously try to join with the same thread, the results are undefined"*. – MrDave1999 Jan 18 '21 at 17:27
  • 2
    Here the join call is coming from a single thread, which people like to call the main thread. So your quote doesn't apply. If, you call pthread_join from multiple threads it would be another story. Note that none of the spawned treads will live beyond the `routine`. – perreal Jan 18 '21 at 17:48
  • Ahh ya, i get it.. :) – MrDave1999 Jan 18 '21 at 18:22
17

First create all the threads, then join all of them:

pthread_t tid[2];

/// create all threads
for (int i = 0; i < 2; i++) {
    pthread_create(&tid[i], NULL, routine, NULL);
}

/// wait all threads by joining them
for (int i = 0; i < 2; i++) {
    pthread_join(tid[i], NULL);  
}

Alternatively, have some pthread_attr_t variable, use pthread_attr_init(3) then pthread_attr_setdetachedstate(3) on it, then pass its address to pthread_create(3) second argument. Thos would create the threads in detached state. Or use pthread_detach as explained in Jxh's answer.

Remember to read some good Pthread tutorial. You may want to use mutexes and condition variables.

You could use frameworks wrapping them, e.g. Qt or POCO (in C++), or read a good C++ book and use C++ threads.

Conceptually, threads have each their call stack and are related to continuations. They are "heavy".

Consider some agent-oriented programming approach: as a rule of thumb, you don't want to have a lot of threads (e.g. 20 threads on a 10 core processor is reasonable, 200 threads won't be unless a lot of them are sleeping or waiting) and and do want threads to synchronize using mutex and condition variables and communicate and/or synchronize with other threads quite often (several times per second). See also poll(2), fifo(7), unix(7), sem_overview(7) with shm_overview(7) as another way of communicating between threads. In general, avoid using signal(7) with threads (read signal-safety(7)...), and use dlopen(3) with caution (probably only in the main thread).

A pragmatical approach would be to have most of your threads running some event loop (using poll(2), pselect(2), perhaps eventfd(2), signalfd(2), ....), perhaps communicating using pipe(7) or unix(7) sockets. See also socket(7).

Don't forget to document (on paper) the communication protocols between threads. For a theoretical approach, read books about π-calculus and be aware of Rice's theorem : debugging concurrent programs is difficult.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 2
    The major issue with this is that pthread_join() is blocking so if you have 512 threads running for 10 hours each +/- 5 hours, threads 1-511 will not be joined until thread 0 completes. And one of these may end a lot earlier. I am not sure detaching them is useful in many cases either. If times were more or less constant we could stagger the creation with a 2 minute delay, say. – mckenzm Jan 20 '21 at 02:00
5

You could start the threads detached, and not worry about joining.

for (int i = 0; i < 2; i++) {
    pthread_t tid;
    pthread_create(&tid, NULL, routine, NULL);
    pthread_detach(tid);
}
pthread_exit(0);

Or, alternatively, you can have the thread that dies report back to the main thread who it is, so that the threads are joined in the order they exited, rather than in the order you created them in.

void *routine(void *arg)
{
    int *fds = (int *)arg;
    pthread_t t = pthread_self();
    usleep((rand()/(1.0 + RAND_MAX)) * 1000000);
    write(fds[1], &t, sizeof(t));
}

int main()
{
    int fds[2];
    srand(time(0));
    pipe(fds);
    for (int i = 0; i < 2; i++) {
        pthread_t tid;
        pthread_create(&tid, NULL, routine, fds);
        printf("created: %llu\n", (unsigned long long)tid);
    }
    for (int i = 0; i < 2; i++) {
        pthread_t tid;
        read(fds[0], &tid, sizeof(tid));
        printf("joining: %llu\n", (unsigned long long)tid);
        pthread_join(tid, 0);
    }
    pthread_exit(0);
}
jxh
  • 69,070
  • 8
  • 110
  • 193
  • I know this is very late, but don't you have to close the fds from pipe? – sgupta Jul 20 '16 at 04:11
  • @user1075375 No. Exiting the process is sufficient. – jxh Jul 20 '16 at 05:50
  • Yeah, but someone might end up using this sample code in a process that does not exit as soon as the worker threads exit. Oh well, too bad for them not knowing to free their fds. – sgupta Jul 20 '16 at 16:48
  • @user1075375 If the process is not exiting, the pipe should be left open for future threads to use. – jxh Jul 20 '16 at 16:57
  • tbh, that's a bit like saying mallocs in main shouldn't be freed because it can be reused. If threads that are spawned later don't use these fds, you're just wasting a resource scarcer than memory on most systems. – sgupta Jul 20 '16 at 20:35
  • @user1075375 There is no point for the master thread to close fds that will just be re-opened later when it spawns new threads. And mallocs can be returned to a reuseable object pool. – jxh Jul 20 '16 at 20:40
0
#include<stdio.h>
#include<pthread.h>

int icnt = 0;   //in non_bss data segment
pthread_mutex_t lock;     //lock variable created stored into bss data segment


void *Thread_count(void* args)      //syncronization 
{
pthread_mutex_lock(&lock);              //lock aquire 
    
icnt++;

for(int x = 1; x <= icnt; x++)
{
    printf("Hello from Thread_count : %d \n",icnt);
}
printf("\n");

pthread_mutex_unlock(&lock);            //release lock  
pthread_exit(NULL);                     //exit from child thread
}


int main()
{

pthread_t threads[4];  //created array of {unsigned long int}
int status = 0;

//creating threads in loop      
for(int i = 1; i <= sizeof(threads)/sizeof(threads[0]); i++)
{
    pthread_create(&threads[i], NULL, &Thread_count, NULL);
}

//waiting for threads in loop
for(int j = 1; j <= sizeof(threads)/sizeof(threads[0]); j++)
{
    pthread_join(threads[j], &status);
    
    printf("Thread number : %d     <-->  Thread status : %d\n",j, status);
}


pthread_exit(0);  //end of main thread
}
user14063792468
  • 839
  • 12
  • 28