- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
问题
什么时候需要使用asio_handler_invoke
来实现仅通过包装处理程序无法完成的操作?
一个规范的示例说明需要asio_handler_invoke
的情况将是理想的。
背景
boost asio文档包含一个如何使用asio_handler_invoke
here的示例,但是我认为这不是为什么要使用调用处理程序的引人注目的示例。在该示例中,您似乎可以进行如下更改(并删除asio_handler_invoke
)并获得相同的结果:
template <typename Arg1>
void operator()(Arg1 arg1)
{
queue_.add(priority_, std::bind(handler_, arg1));
}
asio_handler_invoke
。
asio_handler_invoke
总是像
asio_handler_invoke(h, &h)
一样被调用,这似乎没有多大意义。在什么情况下,参数将不是(基本上)是同一对象的副本?
io_service::run()
,所以可能是我缺少一些来自多线程循环中的经验。
最佳答案
简而言之,包装处理程序和asio_handler_invoke
可完成两项不同的任务:
asio_handler_invoke
挂钩,以自定义处理程序上下文中其他处理程序的调用。 template <typename Handler>
struct custom_handler
{
void operator()(...); // Customize invocation of handler_.
Handler handler_;
};
// Customize invocation of Function within context of custom_handler.
template <typename Function>
void asio_handler_invoke(Function function, custom_handler* context);
// Invoke custom invocation of 'perform' within context of custom_handler.
void perform() {...}
custom_handler handler;
using boost::asio::asio_handler_invoke;
asio_handler_invoke(std::bind(&perform), &handler);
asio_handler_invoke
挂钩的主要原因是允许用户自定义应用程序可能无法直接访问的处理程序的调用策略。例如,考虑由零个或多个对中间操作的调用组成的组合操作。对于每个中间操作,将代表应用程序创建一个中间处理程序,但是应用程序无法直接访问这些处理程序。使用自定义处理程序时,
asio_handler_invoke
挂钩提供了一种在给定上下文中自定义这些中间处理程序的调用策略的方法。
documentation指出:
When asynchronous operations are composed from other asynchronous operations, all intermediate handlers should be invoked using the same method as the final handler. This is required to ensure that user-defined objects are not accessed in a way that may violate the guarantees. This [
asio_handler_invoke
] hooking function ensures that the invoked method used for the final handler is accessible at each intermediate step.
asio_handler_invoke
counting_handler
,并计算在其上下文中调用函数的次数:
template <typename Handler>
class counting_handler
{
void operator()(...)
{
// invoke handler
}
Handler handler_;
};
template <typename Function>
void asio_handler_invoke(Function function, counting_handler* context)
{
// increment counter
// invoke function
}
counting_handler handler(&handle_read);
boost::asio::async_read(socket, buffer, handler);
handle_read
函数由
counting_handler
包装。由于
counting_handler
对计数包装的处理程序被调用的次数不感兴趣,因此其
operator()
将不会增加计数,而只会调用
handle_read
。但是,
counting_handler
对在
async_read
操作中在其上下文中调用的处理程序的数量感兴趣,因此
asio_handler_invoke
中的自定义调用策略将增加一个计数。
counting_handler
类型的具体示例。
operation_counter
类提供了一种使用
counting_handler
轻松包装应用程序处理程序的方法:
namespace detail {
/// @brief counting_handler is a handler that counts the number of
/// times a handler is invoked within its context.
template <class Handler>
class counting_handler
{
public:
counting_handler(Handler handler, std::size_t& count)
: handler_(handler),
count_(count)
{}
template <class... Args>
void operator()(Args&&... args)
{
handler_(std::forward<Args>(args)...);
}
template <typename Function>
friend void asio_handler_invoke(
Function intermediate_handler,
counting_handler* my_handler)
{
++my_handler->count_;
// Support chaining custom strategies incase the wrapped handler
// has a custom strategy of its own.
using boost::asio::asio_handler_invoke;
asio_handler_invoke(intermediate_handler, &my_handler->handler_);
}
private:
Handler handler_;
std::size_t& count_;
};
} // namespace detail
/// @brief Auxiliary class used to wrap handlers that will count
/// the number of functions invoked in their context.
class operation_counter
{
public:
template <class Handler>
detail::counting_handler<Handler> wrap(Handler handler)
{
return detail::counting_handler<Handler>(handler, count_);
}
std::size_t count() { return count_; }
private:
std::size_t count_ = 0;
};
...
operation_counter counter;
boost::asio::async_read(socket, buffer, counter.wrap(&handle_read));
io_service.run();
std::cout << "Count of async_read_some operations: " <<
counter.count() << std::endl;
async_read()
组成的操作将在零个或多个中间
stream.async_read_some()
操作中实现。对于这些中间操作中的每一个,将创建并调用一个类型未指定的处理程序。如果上述
async_read()
操作是根据
2
中间
async_read_some()
操作实现的,则
counter.count()
将为
2
,并且从
counter.wrap()
返回的处理程序将被调用一次。
asio_handler_invoke
钩子(Hook),而是仅在包装的处理程序调用内增加计数,则该计数为
1
,仅反射(reflect)包装的处理程序被调用的次数:
template <class Handler>
class counting_handler
{
public:
...
template <class... Args>
void operator()(Args&&... args)
{
++count_;
handler_(std::forward<Args>(args)...);
}
// No asio_handler_invoke implemented.
};
async_accept
,
async_connect
和
async_read
),但是
async_read
操作将由
2
中间
async_read_some
操作组成:
#include <functional> // std::bind
#include <iostream> // std::cout, std::endl
#include <utility> // std::forward
#include <boost/asio.hpp>
// This example is not interested in the handlers, so provide a noop function
// that will be passed to bind to meet the handler concept requirements.
void noop() {}
namespace detail {
/// @brief counting_handler is a handler that counts the number of
/// times a handler is invoked within its context.
template <class Handler>
class counting_handler
{
public:
counting_handler(Handler handler, std::size_t& count)
: handler_(handler),
count_(count)
{}
template <class... Args>
void operator()(Args&&... args)
{
handler_(std::forward<Args>(args)...);
}
template <typename Function>
friend void asio_handler_invoke(
Function function,
counting_handler* context)
{
++context->count_;
// Support chaining custom strategies incase the wrapped handler
// has a custom strategy of its own.
using boost::asio::asio_handler_invoke;
asio_handler_invoke(function, &context->handler_);
}
private:
Handler handler_;
std::size_t& count_;
};
} // namespace detail
/// @brief Auxiliary class used to wrap handlers that will count
/// the number of functions invoked in their context.
class operation_counter
{
public:
template <class Handler>
detail::counting_handler<Handler> wrap(Handler handler)
{
return detail::counting_handler<Handler>(handler, count_);
}
std::size_t count() { return count_; }
private:
std::size_t count_ = 0;
};
int main()
{
using boost::asio::ip::tcp;
operation_counter all_operations;
// Create all I/O objects.
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0));
tcp::socket socket1(io_service);
tcp::socket socket2(io_service);
// Connect the sockets.
// operation 1: acceptor.async_accept
acceptor.async_accept(socket1, all_operations.wrap(std::bind(&noop)));
// operation 2: socket2.async_connect
socket2.async_connect(acceptor.local_endpoint(),
all_operations.wrap(std::bind(&noop)));
io_service.run();
io_service.reset();
// socket1 and socket2 are connected. The scenario below will:
// - write bytes to socket1.
// - initiate a composed async_read operaiton to read more bytes
// than are currently available on socket2. This will cause
// the operation to complete with multple async_read_some
// operations on socket2.
// - write more bytes to socket1.
// Write to socket1.
std::string write_buffer = "demo";
boost::asio::write(socket1, boost::asio::buffer(write_buffer));
// Guarantee socket2 has received the data.
assert(socket2.available() == write_buffer.size());
// Initiate a composed operation to more data than is immediately
// available. As some data is available, an intermediate async_read_some
// operation (operation 3) will be executed, and another async_read_some
// operation (operation 4) will eventually be initiated.
std::vector<char> read_buffer(socket2.available() + 1);
operation_counter read_only;
boost::asio::async_read(socket2, boost::asio::buffer(read_buffer),
all_operations.wrap(read_only.wrap(std::bind(&noop))));
// Write more to socket1. This will cause the async_read operation
// to be complete.
boost::asio::write(socket1, boost::asio::buffer(write_buffer));
io_service.run();
std::cout << "total operations: " << all_operations.count() << "\n"
"read operations: " << read_only.count() << std::endl;
}
total operations: 4
read operations: 2
async_read()
处理程序由包装两次的处理程序组成。首先由仅计数读取操作的
operation_counter
组成,然后由
operation_counter
包装计数所有操作的结果函子:
boost::asio::async_read(..., all_operations.wrap(read_only.wrap(...)));
counting_handler
的
asio_handler_invoke
实现以支持组合。这导致对每个
operation_counter
进行适当的计数:
template <typename Function>
void asio_handler_invoke(
Function function,
counting_handler* context)
{
++context->count_;
// Support chaining custom strategies incase the wrapped handler
// has a custom strategy of its own.
using boost::asio::asio_handler_invoke;
asio_handler_invoke(function, &context->handler_);
}
asio_handler_invoke
显式调用
function()
,则仅调用最外部包装程序的调用策略。在这种情况下,它将导致
all_operations.count()
为
4
和
read_only.count()
为
0
:
template <typename Function>
void asio_handler_invoke(
Function function,
counting_handler* context)
{
++context->count_;
function(); // No chaining.
}
asio_handler_invoke
挂钩是通过
argument-dependent lookup定位的,因此它基于确切的处理程序类型。使用不支持
asio_handler_invoke
的类型来组合处理程序将防止调用策略的链接。例如,使用
std::bind()
或
std::function
将导致调用默认的
asio_handler_invoke
,从而导致调用自定义调用策略:
// Operations will not be counted.
boost::asio::async_read(..., std::bind(all_operations.wrap(...)));
strand.wrap()
返回的未指定处理程序类型可确保由链和在返回的处理程序的上下文中调用的函数包装的初始处理程序不会同时运行。使用组合操作时,这可以满足许多I/O对象的线程安全要求,因为
strand
可用于与应用程序无法访问的这些中间操作进行同步。
io_service
时,以下代码段可能会调用未定义的行为,因为这两个组合操作的中间操作可能会同时运行,因为
std::bind()
不会调用相应的
asio_handler_hook
:
boost::asio::async_read(socket, ..., std::bind(strand.wrap(&handle_read)));
boost::asio::async_write(socket, ..., std::bind(strand.wrap(&handle_write)));
关于c++ - 何时使用 `asio_handler_invoke`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32857101/
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!