C ++中是否有可等待的队列?
Is there a awaitable queue in c++?
我在我的代码库中大量使用 ppltasks.h
中的 concurrency::task
。
我想找到一个可等待的队列,我可以在其中执行“co_await my_queue.pop()
”。有人实施过吗?
详情:
我有一个将元素推送到队列的生产者线程,另一个接收者线程将在元素到达队列时等待并唤醒。此接收线程可能 wait/wake 同时处理其他任务(使用 pplpp::when_any)。
我不想要一个带有接口的队列,在该接口中我必须轮询 try_pop 方法,因为它很慢,而且我不想要 blocking_pop 方法,因为这意味着我可以'同时处理其他准备好的任务。
这基本上是您的 standard thread-safe queue implementation,但您必须使用 future
来协调不同的线程,而不是 condition_variable
。然后,您可以 co_await
在 pop
编辑的未来 return 上做好准备。
队列的实现将需要保留与未完成的 pop
调用相对应的承诺列表。如果 pop
ing 时队列仍然满,您可以 return 立即准备好未来。您可以使用普通的旧 std::mutex
来同步对底层数据结构的并发访问。
我不知道有任何实现已经做到了这一点,但应该不会太难实现。请注意,虽然管理所有期货会引入一些额外的开销,因此您的队列可能会比经典的基于 condition_variable
的方法效率稍低。
发表了评论,但我还是把它写成答案,因为它很长,我需要格式化。
基本上你有两个选择:
无锁队列,最流行的是这个:
https://github.com/cameron314/concurrentqueue
他们确实有 try_pop,因为它使用原子指针和任何原子方法(例如 std::atomic_compare_exchange_weak)有时会 "fail" 和 return false,所以您被迫对它们进行自旋锁定。
您可能会在 "pop" 中找到将其抽象化的队列,它只调用 "try_pop" 直到它工作,但这在后台是相同的开销。
基于锁的队列:
这些你自己做起来更容易,没有第三方库,只需将你需要的每个方法包装在锁中,如果你想 'peek' 经常查看使用 shared_locks,否则只需 std::lock_guard 就足以保护所有包装器。然而,这就是您所说的 'blocking' 队列,因为在访问期间,无论是读取还是写入,整个队列都将被锁定。
这两个实现没有线程安全的替代方案。如果您在大量使用下需要一个非常大的队列(例如,数百 GB 内存的对象),您可以考虑编写一些自定义混合数据结构,但对于大多数用例,moodycamel 的队列将绰绰有余。
我在我的代码库中大量使用 ppltasks.h
中的 concurrency::task
。
我想找到一个可等待的队列,我可以在其中执行“co_await my_queue.pop()
”。有人实施过吗?
详情: 我有一个将元素推送到队列的生产者线程,另一个接收者线程将在元素到达队列时等待并唤醒。此接收线程可能 wait/wake 同时处理其他任务(使用 pplpp::when_any)。
我不想要一个带有接口的队列,在该接口中我必须轮询 try_pop 方法,因为它很慢,而且我不想要 blocking_pop 方法,因为这意味着我可以'同时处理其他准备好的任务。
这基本上是您的 standard thread-safe queue implementation,但您必须使用 future
来协调不同的线程,而不是 condition_variable
。然后,您可以 co_await
在 pop
编辑的未来 return 上做好准备。
队列的实现将需要保留与未完成的 pop
调用相对应的承诺列表。如果 pop
ing 时队列仍然满,您可以 return 立即准备好未来。您可以使用普通的旧 std::mutex
来同步对底层数据结构的并发访问。
我不知道有任何实现已经做到了这一点,但应该不会太难实现。请注意,虽然管理所有期货会引入一些额外的开销,因此您的队列可能会比经典的基于 condition_variable
的方法效率稍低。
发表了评论,但我还是把它写成答案,因为它很长,我需要格式化。
基本上你有两个选择:
无锁队列,最流行的是这个:
https://github.com/cameron314/concurrentqueue
他们确实有 try_pop,因为它使用原子指针和任何原子方法(例如 std::atomic_compare_exchange_weak)有时会 "fail" 和 return false,所以您被迫对它们进行自旋锁定。
您可能会在 "pop" 中找到将其抽象化的队列,它只调用 "try_pop" 直到它工作,但这在后台是相同的开销。
基于锁的队列:
这些你自己做起来更容易,没有第三方库,只需将你需要的每个方法包装在锁中,如果你想 'peek' 经常查看使用 shared_locks,否则只需 std::lock_guard 就足以保护所有包装器。然而,这就是您所说的 'blocking' 队列,因为在访问期间,无论是读取还是写入,整个队列都将被锁定。
这两个实现没有线程安全的替代方案。如果您在大量使用下需要一个非常大的队列(例如,数百 GB 内存的对象),您可以考虑编写一些自定义混合数据结构,但对于大多数用例,moodycamel 的队列将绰绰有余。