4

From https://computing.llnl.gov/tutorials/pthreads/:

A joining thread can match one pthread_join() call. It is a logical error to attempt multiple joins on the same thread.

Also from "man pthread_join":

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

However, from programmer's point of view, it makes a perfect sense that multiple threads may want to wait for a single thread to complete (similar to barriers).

For example, we may have thread1, thread2 running independently, and we may want both threads to wait until thread3 is completed.

Is there any technical reason behind this restriction?

SHH
  • 3,226
  • 1
  • 28
  • 41
  • 1
    Once `pthread_join()` returns, the last resources associated with the exited thread are released. No other `pthread_join()` can touch that thread, *because nothing of it remains*. It has to be that way, how else would the pthread-library know when to release those resources? If multiple threads *could* join with one pthread, you'd have a permanent resource leak for every exited thread. – EOF Sep 18 '15 at 21:10
  • So, the resource (return value) of a terminated thread is kept in memory until FIRST thread actually joins and claims it? Just like first come first served? – SHH Sep 18 '15 at 21:17
  • 1
    Not quite. It's "first come, first served, and if anyone else comes afterwards there'll be hell to pay". – EOF Sep 18 '15 at 23:22
  • I can say what the reason is but their might be unpleasant work arounds, like pthread_detach and maybe finding some destructor or locks that get released to select for. – jgmjgm Feb 19 '19 at 00:09

2 Answers2

7

I believe the technical reason is that pthread_join is a POSIX standard which, for multithreading, tries to specify only necessary primitives for implementers. Any richer semantics would introduce a costlier implementation and perhaps a more difficult API.

Indeed, POSIX already considers this function to be a convenience, rather than a primitive, in support of a very, very common use case: one thread waits for the termination of one other.

The first paragraph of the POSIX.1-2008 pthread_join RATIONALE is a bit lengthy, but makes many germane observations:

The pthread_join() function is a convenience that has proven useful in multi-threaded applications. It is true that a programmer could simulate this function if it were not provided by passing extra state as part of the argument to the start_routine(). The terminating thread would set a flag to indicate termination and broadcast a condition that is part of that state; a joining thread would wait on that condition variable. While such a technique would allow a thread to wait on more complex conditions (for example, waiting for multiple threads to terminate), waiting on individual thread termination is considered widely useful. Also, including the pthread_join() function in no way precludes a programmer from coding such complex waits. Thus, while not a primitive, including pthread_join() in this volume of POSIX.1-2008 was considered valuable.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
  • Thanks for the specific mention from the document. Learned that pthread_join is there for a convenience (since you can implement more complex waits using other techniques). – SHH Sep 20 '15 at 20:01
0

There is a huge difference between Posix pthreads and Windows Kernel Objects (which I blatantly assume you are familiar with). I find it with unpleasant limitations, and you mentioned just one. There is no real technical reason for this beside current implementation details (yes, thread state is not kept in memory after join, but why?). The other very unpleasant limitation is lack of possiblity to join multiple threads in one call - which probits multiplexing on threads.

Still, millions of pthread-based programms are ran every day, so those limitations are not a show stopper. But indeed, certain tasks would be easier to perform without those.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Just like not all languages have automatic garbage collection, not all thread libraries can track who *could possibly* still have a handle on an exited thread. You might as well ask why you aren't allowed to `free()` an allocation twice. – EOF Sep 18 '15 at 23:20
  • @EOF, No. You do not need to ask 'who still has handle'. You just do not free the handle upon joining. That's it, plain and simple. And if your application runs out of memory because you used all the memories with your thread handles - there is somethig wrong with your application. – SergeyA Sep 18 '15 at 23:31
  • 1
    I disagree, and turn it around: If your thread library can't create new threads in perpetuity - there is something wrong with your thread library. – EOF Sep 18 '15 at 23:34
  • I'm not a fan of windows programming and am a big fan of linux and things like pthreads but I have to agree with this statement. These are frustrating limitations in pthreads. It's worse because I've seen lots of people wrap pthreads for high level languages and also export this limitation due to inspiration or lack thereof that pthreads gives in this regard rather than necessity (IE, the threads gracefully close so they can just pop off their state change to a queue with mutexes to the managing thread). – jgmjgm Feb 19 '19 at 00:08