Reputation: 63
My code is as below:
class MyThread : public std::thread {
int a_;
public:
MyThread(int a)
: std::thread(&MyThread::run, this),
a_(a)
{ }
void run() {
// use a_
}
};
I want to have my own thread class which has all the methods that std::thread provides, so I let MyThread class inherit std::thread. In MyThread's constructor, I pass its member function to std::thread. The compilation is OK, but I am concerned it there a race condition between invoking run() in std::thread's construtor and initializing a_.
Is there a way to make it safe?
Upvotes: 0
Views: 213
Reputation: 218268
but I am concerned it there a race condition between invoking run() in std::thread's construtor and initializing a_.
Yes,
You might reorder member/base:
struct MyThreadData
{
int _a;
};
struct MyThread : MyThreadData, std::thread
{
public:
explicit MyThread(int a) : MyThreadData{a}, _thread([this] {run();}) {}
void run()
{
// thread code here
};
};
Upvotes: 0
Reputation: 104589
Don't do it that way. "Has-a" (composition) has a lot of advantages over "is-a" (inheritance).
class MyThread
{
std::thread _thread;
int _a;
public:
MyThread(int a) : _a(a)
{
_thread = std::thread([this] {run();});
}
void run()
{
// thread code here
};
void join()
{
_thread.join();
}
};
A better approach would be to recognize that the thread and the operation on that thread are two distinct objects:
class WorkerOperation
{
int _a;
public:
WorkerOperation(int a) : _a(a)
{
}
void run()
{
// your code goes here
}
};
And then to create a thread:
shared_ptr<WorkerOperation> spOp = make_shared<WorkerOperation>(42);
std::thread t = std::thread([spOp] {spOp->run();});
And if you really need to pair up the operation and the thread:
std::pair<WorkerOperation, std::thread> threadpair;
threadpair.first = spOp;
threadpair.second = std::move(t);
Upvotes: 3
Reputation: 4713
To fix the error you can write:
MyThread(int a)
:a_(a)
{
(std::thread&)(*this) = std::thread(&MyThread::run, this);
}
This way, the thread is run with initialized a_
.
In general, I don't think it is a good idea to inherit from std::thread. Better make it a private member and run it. Otherwise user can do weird shit if you allow them to cast your class to std::thread& publicly. Like executing a different function than what you intended.
Upvotes: 1