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.

Krusty the Clown
  • 517
  • 6
  • 24
  • 4
    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. – Marc Glisse Feb 06 '22 at 21:37
  • 10
    `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. – mch Feb 06 '22 at 21:39
  • @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? – Krusty the Clown Feb 06 '22 at 21:45
  • See this discussion about the `pthread_t` type: https://stackoverflow.com/questions/33285562/why-and-in-what-sense-is-pthread-t-an-opaque-type – nielsen Feb 06 '22 at 21:45
  • 1
    @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. – Richard Critten Feb 07 '22 at 00:04
  • 2
    @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. – John Bollinger Feb 07 '22 at 13:30

3 Answers3

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
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.

Kaz
  • 55,781
  • 9
  • 100
  • 149
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.

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187