【发布时间】:2022-01-17 07:43:00
【问题描述】:
我想通过异步 Web 请求处理程序将项目添加到一个线程中的队列中:
void handleRequest(item) {
toProcess.push_back(item);
}
有一个后台线程不断处理这些队列项,如下:
while(true) {
for(auto item : toProcess) { doSomething(item); }
toProcess.clear();
}
显然,这不是线程安全的……您可以在 for 循环完成时向 toProcess 添加一个项目,从而在不处理的情况下将其清除。编写这样的程序的最佳模型是什么?
【问题讨论】:
-
std::queue不是一个选项? -
两个线程需要同步,例如使用
mutex。每个在执行调整向量(或队列)大小的操作之前锁定互斥锁,并在完成后释放该互斥锁。这确保了每个线程在另一个线程持有互斥锁时等待。设计考虑的一部分是粒度 - 例如,一个线程是否为单个操作(例如添加或删除一个值)或多个操作(添加多个值,处理然后清除所有值)获取和释放互斥锁。 -
这似乎是队列、互斥体和条件变量三重奏的典型代表。队列的生产者和消费者都需要使用这三个来安全地混合。
-
还有使用无锁队列代替互斥锁的选项。但请注意,这可能听起来更有效,但取决于粒度(推送/弹出频率、作业时间等)和加载它可能比使用互斥锁慢。无锁数据结构提高了可扩展性,但在一个简单的生产者-消费者示例中,互斥锁的开销可能非常低,尤其是在具有廉价用户空间 futex 的操作系统上。
-
std::vector仅在您有固定大小的环形缓冲区时对队列有用。如果您需要支持随机访问迭代器的类似队列的容器,请使用std::deque。
标签: c++ multithreading