用于创建 class 个生成线程的多个实例的 C++ 线程模型

C++ threading model for creating multiple instances of class spawning threads

摘要:

我正在设计一个生成 2 个线程的 class (Inner) - 一个生产者和一个消费者。在一种用法中有一个实例,在另一种情况下有多个实例。

在 Standalone 中,我需要两个线程来继续 writing/reading 消息。但是,如果有多个实例,我需要生成两个线程的代码,但继续创建下一个 class(生成更多线程)。

我的问题是尝试将这两种情况与 std::thread::join()std::thread::detach() 的正确用法相结合。

代码详情:

class Inner 生成一个线程来接收和排队消息,以及第二个线程来读取队列并将消息发送到拥有 Inner 的 class。

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;
};

有两个可能的所有者 classes,SingleInner:

class OneInner
{
    OneInner()
    {
        _inner = std::make_unique<Inner>();
    }

    void receiveMessage(const Message& msg){//Code ommitted}

    std::unique_ptr<Inner> _inner;
};

第二个上下文有多个实例:

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;
};

我不确定如何让 Inner 产生 2 个线程,让它们保持 运行 但在 OneInner 中代码等待,在 MultipleInners 中代码继续创建下一个 Inner.

或者是否有更好的方法来实现这一目标?

如果资源的每个实例都需要一个 class,并且其生命周期与匹配实例的生命周期相同,则最好将其表示为成员变量。

所以只需要Inner的线程成员变量在构造时启动,在销毁时加入:

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;

};