题
什么时候需要asio_handler_invoke通过简单地包装处理程序来实现无法实现的功能?
演示需要的情况的典型示例asio_handler_invoke将是理想的.
背景
boost asio docs包含了一个如何在asio_handler_invoke 这里使用的例子,但我认为它不是一个令人信服的例子,说明为什么要使用调用处理程序.在该示例中,您似乎可以进行如下更改(并删除asio_handler_invoke)并获得相同的结果:
template <typename Arg1>
void operator()(Arg1 arg1)
{
queue_.add(priority_, std::bind(handler_, arg1));
}
Run Code Online (Sandbox Code Playgroud)
同样,在我关于处理程序跟踪的答案中asio_handler_invoke,尽管Tanner Sansbury的回答建议使用调用挂钩作为解决方案,但同样似乎没有必要使用它.
boost用户组上的这个线程提供了更多信息 - 但我不明白其意义.
从我所看到的,它似乎asio_handler_invoke总是被称为asio_handler_invoke(h, &h),似乎没有多大意义.在什么情况下,参数不是(基本上)相同对象的副本?
最后一点 - 我只是io_service::run()从一个线程调用,所以可能是我遗漏了一些来自多线程循环经验的明显东西.
我正在使用VS2010的boost 1.50,使用Windows文件HANDLE读取(与使用套接字的asio相比,这似乎相对不常见).
该
handle_read回调获取到线8并返回与所有所附线1的第一位; 进一步的回调再次从第2行循环,令人作呕:
handle_read具有第1行到第7行的正确内容的预期回调length参数长于预期length,但是从asio流缓冲区中getline提取相应更长的行handle_read回调回收第2行到第7行,然后发生"长混合"线问题LINE 1 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
LINE 2 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
...3--E similarly...
LINE F abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
Run Code Online (Sandbox Code Playgroud)
这是前15行输出(它永远持续):
line #1, length 70, getline() [69] 'LINE 1 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
line #2, length 70, getline() [69] 'LINE 2 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
...line #3 through #6 are fine too...
line #7, length 70, getline() [69] 'LINE 7 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' …Run Code Online (Sandbox Code Playgroud) 阅读boost :: asio的文档,我还不清楚何时需要使用asio :: strand.假设我有一个使用io_service的线程,那么可以安全地在套接字上写入如下吗?
void Connection::write(boost::shared_ptr<string> msg)
{
_io_service.post(boost::bind(&Connection::_do_write,this,msg));
}
void Connection::_do_write(boost::shared_ptr<string> msg)
{
if(_write_in_progress)
{
_msg_queue.push_back(msg);
}
else
{
_write_in_progress=true;
boost::asio::async_write(_socket, boost::asio::buffer(*(msg.get())),
boost::bind(&Connection::_handle_write,this,
boost::asio::placeholders::error));
}
}
void Connection::_handle_write(boost::system::error_code const &error)
{
if(!error)
{
if(!_msg_queue.empty())
{
boost::shared_ptr<string> msg=_msg_queue.front();
_msg_queue.pop_front();
boost::asio::async_write(_socket, boost::asio::buffer(*(msg.get())),
boost::bind(&Connection::_handle_write,this,
boost::asio::placeholders::error));
}
else
{
_write_in_progress=false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
多个线程调用Connection :: write(..)或者我必须使用asio :: strand吗?
我想boost::asio::basic_waitable_timer<std::chrono::steady_clock>安全取消.
根据这个答案,这段代码应该做的工作:
timer.get_io_service().post([&]{timer.cancel();})
Run Code Online (Sandbox Code Playgroud)
我担心这对我不起作用.
难道我做错了什么?
这是我的代码:
#include <iostream>
#include "boost/asio.hpp"
#include <chrono>
#include <thread>
#include <random>
boost::asio::io_service io_service;
boost::asio::basic_waitable_timer<std::chrono::steady_clock> timer(io_service);
std::atomic<bool> started;
void handle_timeout(const boost::system::error_code& ec)
{
if (!ec) {
started = true;
std::cerr << "tid: " << std::this_thread::get_id() << ", handle_timeout\n";
timer.expires_from_now(std::chrono::milliseconds(10));
timer.async_wait(&handle_timeout);
} else if (ec == boost::asio::error::operation_aborted) {
std::cerr << "tid: " << std::this_thread::get_id() << ", handle_timeout aborted\n";
} else {
std::cerr << "tid: " << std::this_thread::get_id() << ", handle_timeout another error\n";
} …Run Code Online (Sandbox Code Playgroud) 我知道OpenSSL,boost asio SSL实现是基于的,不允许并发SSL_read()和SSL_write()(即SSL_read()和SSL_write()由不同的线程执行).
从同一个线程调用SSL套接字上的boost asio async_read()和async_write()是否安全?
谢谢
我是否创建了一个所有 SSL套接字共享的链,或者每个SSL上下文一个链(由任何相关的套接字共享)?
Boost.Asio SSL文档声明了这一点,但它没有提到上下文.我认为这意味着我必须只使用一个链,但我认为这是在OpenSSL支持多线程之前编写的.
SSL和线程
SSL流对象不执行自己的锁定.因此,必须在隐式或显式链中执行所有异步SSL操作.请注意,这意味着在单线程程序中不需要同步(因此不会产生锁定开销).
我很可能只有一个SSL上下文,但我想知道这个链是由SSL上下文还是全局网络服务所拥有的更合适.
我确实提供了一个处理程序CRYPTO_set_locking_callback,以防万一.
我想使用一个用于GUI的线程和一个用于某个套接字IO的工作线程来实现Boost Asio模式.
工作线程将用于boost::asio::io_service管理套接字客户端.套接字上的所有操作仅由工作线程执行.
GUI线程需要从工作线程发送和接收消息.
我无法确定如何使用Boost Asio实现此模式.
我已经用标准的Asio方式实现了套接字通信(我io_service.run()从工作线程调用并使用async_read_some/ async_send).我不需要strands因为io_service.run()只是从工作线程调用.
现在我正在尝试添加跨线程消息队列.我该如何实施呢?
我应该run在io_service从GUI线程呢?
或者我应该使用strandswith post将消息从GUI线程发布到工作线程(不调用io_service.run()或io_service.poll_one()从GUI线程),并使用操作系统的GUI消息循环将消息从工作线程发布到GUI线程?
如果我还需要调用io_service.run()或io_service.poll_one()从GUI线程调用,我是否需要strands在套接字操作上使用,因为它io_service是在两个线程之间共享的?
编辑:为了澄清我的问题,我想尽我所能,使用Boost Asio来实现消息队列,只有当Boost Asio无法完成工作时才依赖其他库.
如果async_read套接字上有a ,则应该有一个内部线程来io_service检查套接字的状态.socket.close()从另一个线程调用是否安全(也许当它运行一个单独的处理程序时io_service)?
我的意思是即使我可以保证我的处理程序不会同时使用asio socket,它是否足够好(考虑内部线程时io_service)?
更新:
我正在使用async_read堆栈协程.与本文档底部的示例非常相似,只是我的有一个额外的函数层调用yield_context.如果我在该示例中调度socket.close()操作,my_strand整个事情是否安全?换句话说,所有相关的操作(堆栈协程的async_read中间async_read_some,隐式处理程序socket.close())是否会通过单个链运行my_strand?
假设在调用 io_service::run() 时,调度了多个 async_read 操作(它们之间可能还有其他操作)。当在 ReadHandler 函数中安排像 async_write 这样的异步操作时会发生什么?
void handler(const boost::system::error_code& error, std::size_t bytes) {
async_write(sock, boost::asio::buffer(wbuf), whandler);
}
Run Code Online (Sandbox Code Playgroud)
也就是说,什么时候会调用async_write?我希望执行顺序是:
1) async_read //1
2) async_write
3) async_read //2
4) async_write
Run Code Online (Sandbox Code Playgroud)
这个执行顺序有保证吗?