我有 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>
在他们不知情的情况下。
与此同时,消费者线程看到 A
或 B
来自队列。
你可以替换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/