5

I understand that pthread_t should be treated as an opaque value, however I don't know how to initialize it when used as a class member, and how can I check for its validity.

Consider this code sample:

class MyClass
{
public:
    pthread_t thread;

    MyClass()
        : thread(0) // Wrong because pthread_t should be an opaque value,
                    // so how should I initialize it?
    {}

    ~MyClass()        
    {
        if( thread ) // Wrong, but how can I verify if it is valid?
            pthread_join(thread, NULL);
    }
};

I also understand that if pthread_create() fails, the pthread_t value may be inconsistent. So I should only rely on the return value from pthread_create(). But this means that I should keep this returned value along with pthread_t and use it to check thread validity? And in this case, how should I initialize in the class constructor this value?

class MyClass
{
public:
    pthread_t thread;
    int threadValid;

    MyClass()
        : thread(0), // Wrong because pthread_t should be an opaque value,
                     // so how should I initialize it?
        , threadValid(1) // pthread_create return zero in case of success,
                         // so I can initialize this to any nonzero value?
    {}

    ~MyClass()        
    {
        if( threadValid == 0 ) // Nonzero means thread invalid.
                               // Is this the correct approach?
        {
            pthread_join(thread, NULL);
            threadValid = 1;
        }
    }
};

I have a Windows API background, and there a thread has its HANDLE value, which may be initialized safely to NULL, and can be checked against NULL, and if CreateThread() fails, it just consistently returns NULL. There's no way, with pthreads, to keep this neat and simple approach?

lornova
  • 6,667
  • 9
  • 47
  • 74
  • http://stackoverflow.com/questions/6276939/is-there-an-invalid-pthread-t-id – Gil Hamilton Jun 16 '15 at 12:38
  • @GilHamilton: that question has no definitive answer on how should I initialize the value and not even on how should I check for thread validity... – lornova Jun 16 '15 at 12:41
  • Yes, but it's pretty much an exact duplicate. The real "answer" is that there simply is no reliable "invalid" sentinel value. – Gil Hamilton Jun 16 '15 at 13:06
  • Your idea of using a `threadValid` boolean is fine. (Your code doesn't look correct for that though. Your constructor is making it say "valid" but you haven't called `pthread_create`) – Gil Hamilton Jun 16 '15 at 13:08
  • 1
    @GilHamilton OP is using a separate `threadValid` member, which is the correct approach; the question is what syntax to use to initialize the `pthread_t` member to an unspecified value. – ecatmur Jun 16 '15 at 13:09
  • @GilHamilton: the costructor should be correct, as I'm keeping 0 as "thread valid" (as returned by `pthread_create`) and 1 as "thread invalid". The destructor, instead, was wrong (now fixed). The problem with the other question is that, apart saying that there's no reliable "invalid" value, doesn't suggests a workaround. – lornova Jun 16 '15 at 13:18

4 Answers4

10

pthread_t is a C type, so it must have a trivial default constructor; so you can just value-initialize it:

    : thread(), // ...

Your usage of threadValid seems somewhat confused. It would be better to make it a bool initially set to false and then only set it true once pthread_create succeeds.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 2
    I like this usage of the default constructor better than not initializing it at all, as suggested by @Pet Johansson, because this way it doesn't seem a forgetfulness during code review. – lornova Jun 16 '15 at 13:26
  • 1
    @Wizard79: Agreed. This is better than the accepted answer under every C++ coding standard I have ever seen. – Nemo May 24 '17 at 21:59
5

But this means that I should keep this returned value along with pthread_t and use it to check thread validity?

Yes, or more simply keep a boolean, like already mentioned.

And in this case, how should I initialize in the class constructor this value?

Don't initialize it, it's not mandatory to initialize members in C++.

Per Johansson
  • 6,697
  • 27
  • 34
  • OK, a boolean is more readable. But this means that I can't use directly the value returned by `pthread_create`... – lornova Jun 16 '15 at 13:21
  • It is guaranteed and documented that the only possible failure code is `-1`? – lornova Jun 16 '15 at 13:28
  • 2
    @Lorenzo, no, [`pthread_create` returns an error code on error](http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_create.html#tag_03_525_05). However, it does return zero on success, so you can still check for non-zero to indicate failure. – pilcrow Jun 16 '15 at 13:30
  • 1
    Right, sorry about that. – Per Johansson Jun 16 '15 at 13:43
3

Unfortunately you can only use a guard variable to know if its value make sense or not. So for instance you can't use 0 because it would be a valid pthread_t on some systems (DG/UX for instance). You should have to use something else to know if the value can be used or not, and you should value-initialize it.

If you can compromise on portability (non production code for instance), consider that on Linux and Android pthread_t should be like an int type, and on Darwin it should be an handle, so it would work if you initialize it to 0.

Giordano
  • 311
  • 2
  • 5
0
pthread_t   thread_handle;
pthread_attr_t  thread_attributes;

pthread_attr_init(&thread_attributes);
pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);

threadValid = (::pthread_create(&thread_handle, &thread_attributes, function, data) == 0);

and when shutting it down:

if (threadValid) {
    ::pthread_join(thread_handle, 0);
}

Don't start your thread in the constructor though.

Jonas Byström
  • 25,316
  • 23
  • 100
  • 147