【发布时间】:2018-02-16 19:16:07
【问题描述】:
我正在寻找一些在 Boost.ASIO 中使用容器数据结构时应用的指导原则。 Boost.ASIO 文档描述了如何使用strand 对象来提供对共享资源的序列化访问,而无需显式线程同步。我正在寻找一种系统化的方式来将strand 同步应用于:
- STL(或类似 STL)容器(例如,
std::deque、std::unordered_map);和 - 无需等待的容器,例如
boost::lockfree::spsc_queue或folly::ProducerConsumerQueue。
下面列出了我的问题。我应该提到我的主要问题是 1-3,但有理由我也准备接受“这些问题没有实际意义/被误导”作为答案;我在问题 4 中详细说明了这一点。
要使任意 STL 容器适应安全同步使用,通过
strand实例执行其所有操作是否足够?为了使无需等待的读写容器适应同步、并发使用,是否足以通过两个不同的
strands 包装其操作,一个用于读取操作,一个用于写入操作? This question 暗示“是”,尽管在该用例中作者描述了使用strand来协调来自多个线程的生产者,而可能只从一个线程中读取。如果上面1-2的答案是肯定的,
strand应该只是通过调用boost::asio::post来管理对数据结构的操作吗?
为了说明 3. 中的问题,这里是来自chat client example 的 sn-p:
void write(const chat_message& msg)
{
boost::asio::post(io_context_,
[this, msg]()
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
do_write();
}
});
}
这里,write_msgs_ 是一个聊天消息队列。我问是因为这是一种特殊情况,对post 的调用可能会调用组合的异步操作(do_write)。如果我只是想从队列中推送或弹出怎么办?举一个高度简化的例子:
template<typename T>
class MyDeque {
public:
push_back(const T& t);
/* ... */
private:
std::deque<T> _deque;
boost::asio::io_context::strand _strand
};
那么应该MyDeque::push_back(const T& t)就打电话
boost::asio::post(_strand, [&_deque]{ _deque.push_back(t); })
其他操作也类似?还是boost::asio::dispatch 更合适?
- 最后,我知道并发向量、哈希映射等有很多健壮的实现(例如,Intel Thread Building Blocks Containers)。但似乎在受限制的用例下(例如,只维护一个活跃聊天参与者的列表、存储最近的消息等),完全并发的向量或哈希映射的力量可能有点矫枉过正。确实是这样,还是我最好只使用完全并发的数据结构?
【问题讨论】:
标签: c++ multithreading concurrency boost-asio