Home > Software engineering >  c Thread handling in class
c Thread handling in class

Time:06-29

I would like to create a object in which I can start a thread and have a function to join withe the created thread. Everything insight the object, so that the thread is a private component of the object.

I have tried a bit and got those Results. Could some of you explain me what I have done wrong, and why I get this errors?

A.h

#include <thread>

class A{
    std::thread a;
    public:
    //this should be a void function 
    std::thread startThread();

    void join();
    void (*threadFunction)() = nullptr;
};

and the A.cpp

#include "../header/A.h"

std::thread A::startThread()
{
    std::thread a((*threadFunction));
    return a;
}

void A::join()
{
    a.join();   
}

main.cpp

void newFunc(){
    std::cout<<"I'm a thread"<<std::endl;
}

int main(){
    auto object = new A();
    object->threadFunction = &newFunc;
    //Version 1) Error "terminate called without an active exception"
    object->startThread();
    object->join();
    /*
      Version 2) terminate called after throwing an instance of 'std::system_error' 
      I'm a thread
      what():  Invalid argument
    */
    auto value = object->startThread();
    object->join();
    //Version 3) I'm a thread
    auto value = object->startThread();
    value.join();
}

I don't see the difference. I have stored the thread in the object, so it is not lost... and when I store the return value and don't use it, its almost fine... but not really ... and directly join() is perfect ... I don't get it :D

Please help me

CodePudding user response:

std::thread A::startThread()
{
    std::thread a((*threadFunction));
    return a;
}

Does not interact with the member variable a, but it creates a new local variable std::thread object and then moves it to the result (unless the move is optimized out). The thread A::a always remains the default constructed one. A default constructed thread object is non-joinable, i.e. throws an exception on the call of std::thread::join. The only thread join can be called for without causing an exception is the thread object returned from the function.

If you don't join the returned thread and its destructor runs (happens when you drop the temporary thread object returned (Version 1)), std::terminate shuts your program down.

To make this work you need to move assign a newly created thread to the member variable and not return the thread object or just return a reference to it:

void A::startThread()
{
    a = std::thread(threadFunction);
}

or

std::thread& A::startThread()
{
    a = std::thread(threadFunction);
    return a;
}

I wouldn't recommend the second alternative, it drastically reduces your ability to enforce class invariants with regards to the thread lifecycle.

  • Related