C++ boost ASIO和线程之间的消息传递
我正在设计一个websocket服务器,它接收消息并将其保存到嵌入式数据库中。用于阅读我正在使用的消息。要将消息保存到嵌入式数据库,我会看到前面有几个选项:C++ boost ASIO和线程之间的消息传递,c++,multithreading,sockets,boost,C++,Multithreading,Sockets,Boost,我正在设计一个websocket服务器,它接收消息并将其保存到嵌入式数据库中。用于阅读我正在使用的消息。要将消息保存到嵌入式数据库,我会看到前面有几个选项: 当我通过同一线程收到消息时,立即同步保存消息 在单独的线程上异步保存消息 我很确定第二个答案就是我想要的。但是,我不知道如何将消息从套接字线程传递到IO线程。我看到以下选项: 每个线程使用一个io服务,并使用在线程之间进行通信。在这里,我不得不担心锁争用。我应该吗 使用Linux域套接字在线程之间传递消息。据我所知,没有锁争用。在这里,我可
- 消息的长度正好为8个字节
- 无法使用外部数据库。数据库必须嵌入到正在运行的数据库中 过程
- 我正在考虑将其用作嵌入式系统 数据库
io\u服务
——您可以创建额外的线程,通过提供boost::asio::io\u service::run
作为线程函数来处理io\u服务
中发生的事件。对于通过网络套接字从客户端接收8字节的消息来说,这应该具有很好的扩展性
对于在数据库中存储消息,它取决于数据库和接口。如果它是多线程的,那么您也可以从接收消息的线程向DB发送每条消息。否则,我可能会设置一个boost::lockfree::queue
,其中一个读卡器线程提取项目并将其发送到数据库,io_服务
线程在它们到达时将新消息附加到队列中
这是最有效的方法吗?我不知道。这绝对是简单的,并给你一个基线,你可以概况,如果它不够快,你的情况。但我建议不要一开始就设计更复杂的东西:你根本不知道你是否需要它,除非你对你的系统了解很多,否则实际上不可能说复杂的方法是否比简单的方法表现得更好。void Consumer(无锁::队列&消息队列){
void Consumer( lockfree::queue<uint64_t> &message_queue ) {
// Connect to database...
while (!Finished) {
message_queue.consume_all( add_to_database ); // add_to_database is a Functor that takes a message
cond_var.wait_for( ... ); // Use a timed wait to avoid missing a signal. It's OK to consume_all() even if there's nothing in the queue.
}
}
void Producer( lockfree::queue<uint64_t> &message_queue ) {
while (!Finished) {
uint64_t m = receive_from_network( );
message_queue.push( m );
cond_var.notify_all( );
}
}
//连接到数据库。。。
当(!完成){
message_queue.consume_all(add_to_database);//add_to_database是接受消息的函子
cond_var.wait_for(…);//使用定时等待以避免丢失信号。即使队列中没有任何内容,也可以使用_all()。
}
}
无效生产者(无锁::队列和消息队列){
当(!完成){
uint64_t m=从_网络()接收_;
消息队列推送(m);
cond_var.notify_all();
}
}
我认为您不想使用unix套接字,它总是需要系统调用并通过内核传递数据。这通常更适合作为进程间机制而不是线程间机制
除非您的数据库API要求所有调用都来自同一个线程(我对此表示怀疑),否则您不必为它使用单独的boost::asio::io_服务。我将在现有的io_服务
实例上创建一个实例,并使用member函数(而不是io_服务::post()
)来执行任何阻塞数据库任务。以这种方式使用串
可以保证最多有一个线程可能被阻止访问数据库,从而使io_服务
实例中的所有其他线程都可用于服务非数据库任务
为什么这比使用单独的io\u服务
实例要好?一个优点是,拥有一个带有一组线程的单个实例稍微更易于编码和维护。另一个次要的优点是,如果可以,使用strand::dispatch()
将在当前线程中执行(即如果strand
中没有任务正在运行),这可能会避免上下文切换
对于最终的优化,我同意使用一个特殊的队列,其排队操作不能进行系统调用,这可能是最快的。但是,考虑到生产者有网络i/o,消费者有磁盘i/o,我看不出队列的实现将如何成为您的瓶颈。假设在您的情况下使用cxx11的限制不是太难,我会尝试使用来对嵌入式DB进行异步调用 在基准测试/评测之后,我发现facebook folly的实现速度最快,至少有50%的优势。如果我使用,那么套接字线程几乎没有开销,IO线程仍然很忙。系统调用的数量也比其他队列实现少得多
boost中包含cond变量的SPSC队列速度较慢。我不知道这是为什么。这可能与愚蠢队列使用的自适应旋转有关
此外,消息传递(本例中为UDP域套接字)的速度慢了几个数量级,尤其是对于较大的消息。这可能与复制数据两次有关。我会使用BooSt.ASIO与设备等通信,但是如果你需要线程间通信,我不会认为这是正确的选择。也许您可以使用boost.lockfree中提供的无锁缓冲区?spsc_队列为我做了很多次。我也认为这是最快的方式,在performan