C ++中无锁多个生产者多个消费者

时间:2016-12-14 18:28:41

标签: c++ buffer producer-consumer

我必须用C ++编写一个多生产者 - 消费者系统,但是我试图将模型的每个部分(具有正确缓冲区的线程)放在一起。该模型的基本功能是:我有一个执行函数的初始线程。返回的结果需要放在未确定数量的缓冲区中,因为函数进程的每个元素都不同,需要在单个线程中处理。然后,在存储在缓冲区中的数据中,另一个n线程需要获取此缓冲区的数据以执行另一个函数,并且需要将此返回值再次放入某些缓冲区中。

目前我已经创建了这个缓冲区结构:

template <typename T>
class buffer {
public:
  atomic_buffer(int n);
  int bufSize() const noexcept;
  bool bufEmpty() const noexcept;
  bool full() const noexcept;
  ~atomic_buffer() = default;


  void put(const T & x, bool last) noexcept;
  std::pair<bool,T> get() noexcept;

private:
  int next_pos(int p) const noexcept;

private:
  struct item {
    bool last;
    T value;
  };
  const int size_;
  std::unique_ptr<item[]> buf_;
  alignas(64) std::atomic<int> nextRd_ {0};
  alignas(64) std::atomic<int> nextWrt_ {0};
};

我还创建了一个vector结构,它存储一个集合un缓冲区,以满足不确定数量的线程的必要性。

std::vector<std::unique_ptr<locked_buffer<std::pair<int, std::vector<std::vector<unsigned char>>>>>> v1;

for(int i=0; i<n; i++){     
v1.push_back(std::unique_ptr<locked_buffer<std::pair<int,std::vector<std::vector<unsigned char>>>>> (new locked_buffer<std::pair<int, std::vector<std::vector<unsigned char>>>>(aux)));  
}

编辑:

Flowchart of the model

1 个答案:

答案 0 :(得分:2)

在不了解更多上下文的情况下,这看起来像是标准线程池的应用程序。您有不同的任务排队到同步队列(如您所在的buffer类)。线程池的每个工作线程轮询此队列并每次处理一个任务(例如,通过执行run()方法)。他们将结果写回另一个同步队列。

每个工作线程都有一个自己的线程本地输入和输出缓冲区对。他们不需要同步,因为只能从所有者线程本身访问它们。

enter image description here

编辑:实际上,我认为这可以简化很多:只需使用线程池和一个同步队列。工作线程可以将新任务直接排入队列。图中的每个线程都对应一种类型的任务,并实现一个通用的Task接口。 你不需要多个缓冲区。您可以使用多态并将所有内容放在一个缓冲区中。

编辑2 - 线程池说明:
线程池只是一个概念。忘记池方面,使用固定数量的线程。主要思想是:有N个线程可以处理任何类型的任务,而不是让几个线程具有特定的功能。其中N是CPU的核心数。

你可以改变这个

enter image description here

进入

enter image description here

工作线程执行类似以下操作。请注意,这是简化的,但您应该明白这一点。

void Thread::run(buffer<Task*>& queue) {
    while(true) {
        Task* task = queue.get();
        if(task)
            task->execute();
        while(queue.isEmpty())
            waitUntilQueueHasElement();
    }
}

您的任务实现了一个通用接口,因此您可以将Task*指针放入一个队列中:

struct Task {
    virtual void execute() = 0;
}

struct Task1 : public Task {
    virtual void execute() override {
        A();
        B1();
        C();
    }
}

...

另外,帮自己一个忙,并使用typedef;)

`std::vector<std::unique_ptr<locked_buffer<std::pair<int, std::vector<std::vector<unsigned char>>>>>> v1;`  

变为

typedef std::vector<std::vector<unsigned char>> vector2D_uchar;
typedef std::pair<int, vector2D_uchar> int_vec_pair;
typedef std::unique_ptr<locked_buffer<int_vec_pair>> locked_buffer_ptr;
std::vector<locked_buffer_ptr> v1;