Why does pthread_join not take a thread pointer?
Asked Answered
H

3

6

Pretty self explanatory question. For example, the header for pthread_create shows it takes a pointer to a thread:

int WINPTHREAD_API pthread_create(pthread_t *th, const pthread_attr_t *attr, void *(* func)(void *), void *arg);

OK, makes sense, you allocate a pthread in memory then pass a pointer to pthread_create so it gets initialized... but now looking at the header for pthread_join:

int WINPTHREAD_API pthread_join(pthread_t t, void **res);

It takes a copy of the pthread_t. I just don't get why it doesn't take a pointer to that already existing thread, rather than copying it and passing it over; it seems like if anything, doing so would cause more problems and more memory use. Am I missing something? I read the manpage, it doesn't seem to offer a reason to this.

Health answered 6/2, 2022 at 21:34 Comment(6)
pthread_t is already an id, almost the same as a pointer. Passing it by pointer would be redundant, unless you intend to modify it.Judaist
pthread_create has to change the value, therefore it needs it as a pointer. pthread_join only needs the value, so pass by value is fine.V2
@MarcGlisse crap, I was under the impression pthread_t was a struct, I didn't realize it was just an ID... on that note, any particular reason pthread_create doesn't just return a pthread_t if it's just an ID?Health
See this discussion about the pthread_t type: #33286062Pippin
@MarcGlisse "...doesn't just return a pthread_t..." - pthread_create is a C interface it need to be able to return an error code, it can't throw an exception.Wickman
@TheCornInspector, pthread_t could be a struct. It could also be a pointer or an integer. To the extent that Marc is asserting that it is similar in form to a pointer, his claim is not supported by the specifications. But he is absolutely correct that objects of that type serve the role of an ID. POSIX has defined the pthreads interfaces in a way that affords implementations considerable flexibility for how they define pthread_t, among other things.Dobby
D
5

It takes a copy of the pthread_t.

Yes.

I just don't get why it doesn't take a pointer to that already existing thread,

pthread_t is a thread identifier. The specs consistently refer to it that way. Copying it does not duplicate the thread itself, nor consume more memory than one pthread_t occupies.

rather than copying it and passing it over; it seems like if anything, doing so would cause more problems and more memory use.

It does not necessarily cause more memory use, as a pthread_t is not necessarily larger than a pointer. It might be a pointer, or an integer. Even if it is a structure, however, there is no reason to think that it so large that passing it by value presents a significant problem, because the specifics are under control of the pthreads implementation. Why would implementers shoot themselves in the foot that way? Note well that passing a structure by value is not inherently less efficient than passing a pointer.

As for problems other than excessive memory use, you would have to be more specific, but I don't see any issues inherent in accessing a copy of a thread identifier directly vs. accessing a common identifier object indirectly, for the purposes of those functions that accept a pthread_t by value.

Am I missing something?

I suspect that your concerns are tied up in a misunderstanding of type pthread_t as somehow carrying data supporting thread operation as opposed to simply identifying a thread.

You may also be supposing that pthreads is a library, with a particular implementation, whereas in fact, it is first and foremost a specification, designed to afford multiple implementations. This is part of the reason for defining abstract data type pthread_t instead of specifying int or struct something * -- implementations can choose what actual type to use.

Perhaps you are also focusing too closely on the API functions. Even if in some particular implementation, passing a pthread_t by value to, say, pthread_join() were less efficient than passing a pointer to one, how much of an impact do you suppose that would actually have? pthread_join() is called infrequently, and only in cases where the caller is prepared to block. What does it matter if argument passing consumes a few more nanoseconds than it might otherwise do?

I read the manpage, it doesn't seem to offer a reason to this.

Few manual pages provide rationale for function design, but I think the most likely explanation is essentially that form follows function. Those functions that receive a pthread_t by value do so because they do not need or want to modify the caller's value. The functions' designs reflect that.

Dobby answered 7/2, 2022 at 14:46 Comment(0)
P
2

A pthread_t is a small object which identifies a thread. It could be a pointer, integer or perhaps a tiny structure. The pthread_t isn't actually the thread itself any more than a HWND object in Win32 is the window itself.

The pthread_create function returns this identifier via a pointer pointer because it already returns a value of type int for error indication. Other functions take pthread_t by value.

For instance, to compare whether two pthread_t objects refer to the same thread, you should use pthread_equal, which takes two pthread_t parameters. It's possible that all this function does is compare the two values using ==, but doing that directly wouldn't be as portable. It won't even compile if pthread_t happens to be a small structure.

Pretended answered 7/2, 2022 at 17:58 Comment(0)
T
2

One thing to note is that pthread is a C API. Unlike C++ which has constructors, copying a C variable is guaranteed to be reasonably inexpensive. The worst case would be a type that is a large structure but even then, it's only a memcpy. This is different than C++ where a copy can invoke an arbitrarily expensive constructor.

Thunder answered 21/2, 2022 at 18:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.