Reputation: 30615
Abstract:
I am designing a class (Inner
) which spawns 2 threads- a producer and a consumer. In one usage there is one instance and in another context there are multiple instances.
In Standalone I need the two threads to continue writing/reading messages. However, if there's multiple instances I need the code to spawn the two threads but continue to create the next class (to spawn more threads).
My problem is trying to combine these two scenarios with correct usage of std::thread::join()
and std::thread::detach()
.
Code details:
The class Inner
spawns a thread to receive and queue messages and a second thread to read the queue and send messages to the class owning Inner
.
template<Owner>
class Inner
{
Inner(Owner& owner) : _owner(owner)
{
// Spawn thread to receive packets and put on queue
// Spawn thread to read from queue
}
void receiveMessage(const Message& msg)
{
// Ommitted locks etc for simplicty
_queue.push(msg);
}
void readFromQueue()
{
// Ommitted loop, locks etc for simplicty
_owner.receiveMessage(msg);
}
Owner& _owner;
std::queue<Message> _queue;
};
There are two possible owner classes, SingleInner
:
class OneInner
{
OneInner()
{
_inner = std::make_unique<Inner>();
}
void receiveMessage(const Message& msg){//Code ommitted}
std::unique_ptr<Inner> _inner;
};
and the second context has multiple instances:
class MultipleInners
{
MultipleInners()
{
// Need to create multiple instances of Inner, each with Inner's two threads running
}
void receiveMessage(const Message& msg){//Code ommitted}
std::vector<std::unique_ptr<Inner>> _inners;
};
I'm unsure how I can allow Inner
to spawn 2 threads, have them keep running but in OneInner
the code waits and in MultipleInners
the code continues to create the next Inner
.
Or if there's a completely better way of achieving this?
Upvotes: 2
Views: 388
Reputation:
A resource of which you need one for each instance of a class, and who's lifetime is the same as that of the matching instance is best represented as a member variable.
So just make the threads member variables of Inner
that are launched at construction, and joined at destruction:
template<Owner>
class Inner
{
Inner(Owner& owner)
: _owner(owner)
, _recv_thread([this](){readFromQueue();}),
, _read_thread([this](){receiveLoop();}),
{
}
~Inner() {
_recv_thread.join();
_read_thread.join();
}
void receiveLoop() {
while(...) {
//etc...
receiveMessage(msg);
}
}
void receiveMessage(const Message& msg)
{
// Ommitted locks etc for simplicty
_queue.push(msg);
}
void readFromQueue()
{
// Ommitted loop, locks etc for simplicty
_owner.receiveMessage(msg);
}
Owner& _owner;
std::queue<Message> _queue;
// Make sure these are the last members, so that _owner and _queue
// are constructed already when the threads start
std::thread _recv_thread;
std::thread _read_thread;
};
Upvotes: 2