C++11 如何在 1 个线程中使用条件变量处理 2 个线程安全队列

标签 c++ multithreading legacy condition-variable

我有 2 个连接对象在它们自己的线程上运行,每个线程将不同的数据放入在主线程中运行的相应队列中。所以主线程有 2 个队列,当这些队列中的任何一个发出它已放入数据的信号时需要被唤醒。我写了一个线程安全的队列,它封装了 pushing、popping 和 signaling theadsafe_queue 中的条件变量。但它似乎行不通,因为在主循环中它可以阻塞在第一个队列中,数据可以进入第二个队列而不被唤醒,反之亦然。
我是否必须在 2 个队列之间共享相同的条件变量和互斥量。 我可以修改我的 threadsafe_queue 以将条件变量和互斥量作为参数并将相同的参数传递给每个队列。 或者我在想也许可以使用 wait_until 和每个队列的计时器,以便在超时时有机会检查每个队列,但这似乎效率不高。 主处理线程有很多带有静态对象/变量和容器的遗留代码,因此如果不引入很多锁就不能将其拆分为 2 个线程。 你认为最好的方法是什么。

最佳答案

合并队列。

或者,写一个流媒体系统。生产者不需要知道他们的数据去了哪里;它必须去。他们需要:

template<class T>
using sink=std::function<void(T)>;

发送他们的数据。

监听器不需要知道数据来自哪里。它需要一个来源:

template<class T>
using source= sink<sink<T>>;

现在他们在不同的线程上;所以你需要一种方法来从 A 到 B 获取数据。

template<class T>
struct threadsafe_queue {
  sink<T> get_sink();
  source<T> get_source();
};

在其中维护您的互斥体、条件变量和缓冲区。

现在是有趣的部分。如果我们有 X=variant<A,B> , 然后 sink<X>可以转换为sink<A> (同时 source<A> 可以转换为 source<X> )。

所以如果线程 1 产生 A线程 2 产生 B , 它们都可以输入 sink<X>在他们不知情的情况下。

与此同时,消费者线程看到 AB来自队列。

你可以替换source<T>=sink<sink<T>>source<T>=std::function<std::optional<T>()> ,完成后返回空。我喜欢源是汇的汇;使用是:

void print_ints( source<int> src ) {
  src([](int x){ std::cout<<x<<','; });
  std::cout<<"\n";
}

与我不太喜欢的相比:

void print_ints( source<int> src ) {
  while(auto x=src()){std::cout<<*x<<','; };
  std::cout<<"\n";
}

顺便说一句,您可以标记源/接收器类型并重载 |并添加 pipe<In,Out>等等

但这在这里没有用。

关于C++11 如何在 1 个线程中使用条件变量处理 2 个线程安全队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51645341/

相关文章:

c# - 如何将 BitmapImage 从后台线程传递到 WPF 中的 UI 线程?

python - 从 C++ 获取 python 可执行文件的完整路径

c++ - 我如何在 C++ 中追加一个 struct Person

c++ - 阅读 getchar_unlocked 失败案例

java - CompletableFuture的完成处理程序在哪个线程中执行?

multithreading - 在 ColdFusion 中,为什么 Set & Forget 子线程不能访问 session /客户端范围?

architecture - 重建遗留应用程序的策略

java - 方法取决于不存在的组 - Testng

ruby-on-rails - 如何手动将用户添加到 Rails 应用程序?

c++ - winsock recv 返回 0 而没有从对等端关闭,与为控制台编译时的行为不同