鲍里斯的 article向我们展示了如何创建 boost::asio 的扩展。我尝试在已注册的信号上添加 signal_set 和 async_wait。然后程序挂起,直到触发第二个 SIGINT。虽然,我想只在一个信号内正确完成它。
这是我的代码。我在 Ubuntu 上使用 gcc-4.6.3 和 boost-1.52.0 对其进行了测试。
编译-
gcc -I/boost_inc -L/boot_lib main.cpp -lpthread -lboost_system -lboost_thread
#include <boost/asio.hpp>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <cstddef>
template <typename Service>
class basic_timer
: public boost::asio::basic_io_object<Service>
{
public:
explicit basic_timer(boost::asio::io_service &io_service)
: boost::asio::basic_io_object<Service>(io_service)
{}
void wait(std::size_t seconds)
{ return this->service.wait(this->implementation, seconds); }
template <typename Handler>
void async_wait(std::size_t seconds, Handler handler)
{ this->service.async_wait(this->implementation, seconds, handler); }
};
class timer_impl;
template <typename TimerImplementation = timer_impl>
class basic_timer_service
: public boost::asio::io_service::service
{
public:
static boost::asio::io_service::id id;
explicit basic_timer_service(boost::asio::io_service &io_service)
: boost::asio::io_service::service(io_service),
async_work_(new boost::asio::io_service::work(async_io_service_)),
async_thread_(
boost::bind(&boost::asio::io_service::run, &async_io_service_))
{}
~basic_timer_service()
{
async_work_.reset();
async_io_service_.stop();
async_thread_.join(); // program is blocked here until the second
// signal is triggerd
async_io_service_.reset();
}
typedef boost::shared_ptr<TimerImplementation> implementation_type;
void construct(implementation_type &impl)
{
impl.reset(new TimerImplementation());
}
void destroy(implementation_type &impl)
{
impl->destroy();
impl.reset();
}
void wait(implementation_type &impl, std::size_t seconds)
{
boost::system::error_code ec;
impl->wait(seconds, ec);
boost::asio::detail::throw_error(ec);
}
template <typename Handler>
class wait_operation
{
public:
wait_operation(
implementation_type &impl,
boost::asio::io_service &io_service,
std::size_t seconds, Handler handler)
: impl_(impl),
io_service_(io_service),
work_(io_service),
seconds_(seconds),
handler_(handler)
{}
void operator()() const
{
implementation_type impl = impl_.lock();
if (!io_service_.stopped() && impl)
{
boost::system::error_code ec;
impl->wait(seconds_, ec);
this->io_service_.post(
boost::asio::detail::bind_handler(handler_, ec));
}
else
{
this->io_service_.post(
boost::asio::detail::bind_handler(
handler_, boost::asio::error::operation_aborted));
}
}
private:
boost::weak_ptr<TimerImplementation> impl_;
boost::asio::io_service &io_service_;
boost::asio::io_service::work work_;
std::size_t seconds_;
Handler handler_;
};
template <typename Handler>
void async_wait(
implementation_type &impl,
std::size_t seconds, Handler handler)
{
this->async_io_service_.post(
wait_operation<Handler>(
impl, this->get_io_service(), seconds, handler));
}
private:
void shutdown_service()
{}
boost::asio::io_service async_io_service_;
boost::scoped_ptr<boost::asio::io_service::work> async_work_;
boost::thread async_thread_;
};
class timer_impl
{
public:
timer_impl()
{}
~timer_impl()
{}
void destroy()
{}
void wait(std::size_t seconds, boost::system::error_code &ec)
{
sleep(seconds);
ec = boost::system::error_code();
}
};
typedef basic_timer<basic_timer_service<> > timer;
template <typename TimerImplementation>
boost::asio::io_service::id basic_timer_service<TimerImplementation>::id;
void wait_handler(const boost::system::error_code &ec)
{
std::cout << "5 s." << std::endl;
}
int main()
{
{
boost::asio::io_service io_service;
boost::asio::signal_set signals(io_service);
timer t(io_service);
signals.add(SIGINT);
signals.async_wait(
boost::bind(&boost::asio::io_service::stop, &io_service));
t.async_wait(2, wait_handler);
std:: cout << "async called\n" ;
io_service.run();
}
{ // this block will not be executed
boost::asio::io_service io_service;
timer t(io_service);
t.async_wait(2, wait_handler);
std:: cout << "async called\n" ;
io_service.run();
}
return 0;
}
最佳答案
在尝试了 example 之后由 asio 的作者提供,我遇到了同样的行为。因此,我深入研究了库源代码,发现源代码使用了 io_service_impl 的接口(interface),而不是 io_service 的接口(interface)。此外,发布到 io_service_impl 的operation functor 与 io_service 调用的不同。总之,我决定根据asio的内部接口(interface)重写timer的例子。
我在此展示重写的计时器示例。
#include <boost/asio.hpp>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <cstddef>
#define get_service_impl(X) \
ba::use_service<bad::io_service_impl>(X)
namespace ba = boost::asio;
namespace bad = boost::asio::detail;
// Nothing changed
template <typename Service>
class basic_timer
: public boost::asio::basic_io_object<Service>
{
public:
explicit basic_timer(boost::asio::io_service &io_service)
: boost::asio::basic_io_object<Service>(io_service)
{}
void wait(std::size_t seconds)
{ return this->service.wait(this->implementation, seconds); }
template <typename Handler>
void async_wait(std::size_t seconds, Handler handler)
{ this->service.async_wait(this->implementation, seconds, handler); }
};
// Nothing changed
class timer_impl
{
public:
void wait(std::size_t seconds, boost::system::error_code &ec)
{
sleep(seconds);
ec = boost::system::error_code();
}
};
// ----- Change a lot! --------
class basic_timer_service
: public boost::asio::io_service::service
{
public:
typedef boost::asio::detail::socket_ops::shared_cancel_token_type
implementation_type;
static boost::asio::io_service::id id;
explicit basic_timer_service(boost::asio::io_service &io_service)
: boost::asio::io_service::service(io_service),
io_service_impl_(get_service_impl(io_service)),
work_io_service_( new boost::asio::io_service ),
work_io_service_impl_(get_service_impl(*work_io_service_)),
work_(new ba::io_service::work(*work_io_service_)),
work_thread_() // do not create thread here
{}
~basic_timer_service()
{ shutdown_service(); }
void construct(implementation_type &impl)
{ impl.reset(new timer_impl()); }
void cancel(implementation_type &impl)
{
impl.reset((void*)0, boost::asio::detail::socket_ops::noop_deleter());
}
void destroy(implementation_type &impl)
{ impl.reset(); }
void shutdown_service()
{
work_.reset();
if(work_io_service_.get()){
work_io_service_->stop();
if (work_thread_.get()){
work_thread_->join();
work_thread_.reset();
}
}
work_io_service_.reset();
}
void wait(implementation_type &impl, std::size_t seconds)
{
boost::system::error_code ec;
// XXX I not sure this is safe
timer_impl *impl_ptr = static_cast<timer_impl*>(impl.get());
impl_ptr->wait(seconds, ec);
boost::asio::detail::throw_error(ec);
}
template <typename Handler>
class wait_operation
: public boost::asio::detail::operation
{
public:
BOOST_ASIO_DEFINE_HANDLER_PTR(wait_operation);
// namespace ba = boost::asio
// namespace bad = boost::asio::detail
wait_operation(
bad::socket_ops::weak_cancel_token_type cancel_token,
std::size_t seconds,
bad::io_service_impl& ios,
Handler handler)
: bad::operation(&wait_operation::do_complete),
cancel_token_(cancel_token),
seconds_(seconds),
io_service_impl_(ios),
handler_(handler)
{}
static void do_complete(
bad::io_service_impl *owner,
bad::operation *base,
boost::system::error_code const & /* ec */ ,
std::size_t /* byte_transferred */ )
{
wait_operation *o(static_cast<wait_operation*>(base));
ptr p = { boost::addressof(o->handler_), o, o};
// Distinguish between main io_service and private io_service
if(owner && owner != &o->io_service_impl_)
{ // private io_service
// Start blocking call
bad::socket_ops::shared_cancel_token_type lock =
o->cancel_token_.lock();
if(!lock){
o->ec_ = boost::system::error_code(
ba::error::operation_aborted,
boost::system::system_category());
}else{
timer_impl *impl = static_cast<timer_impl*>(lock.get());
impl->wait(o->seconds_, o->ec_);
}
// End of blocking call
o->io_service_impl_.post_deferred_completion(o);
p.v = p.p = 0;
}else{ // main io_service
bad::binder1<Handler, boost::system::error_code>
handler(o->handler_, o->ec_);
p.h = boost::addressof(handler.handler_);
p.reset();
if(owner){
bad::fenced_block b(bad::fenced_block::half);
boost_asio_handler_invoke_helpers::invoke(
handler, handler.handler_);
}
}
}
private:
bad::socket_ops::weak_cancel_token_type cancel_token_;
std::size_t seconds_;
bad::io_service_impl &io_service_impl_;
Handler handler_;
boost::system::error_code ec_;
};
template <typename Handler>
void async_wait(
implementation_type &impl,
std::size_t seconds, Handler handler)
{
typedef wait_operation<Handler> op;
typename op::ptr p = {
boost::addressof(handler),
boost_asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0};
p.p = new (p.v) op(impl, seconds, io_service_impl_, handler);
start_op(p.p);
p.v = p.p = 0;
}
protected:
// Functor for runing background thread
class work_io_service_runner
{
public:
work_io_service_runner(ba::io_service &io_service)
: io_service_(io_service) {}
void operator()(){ io_service_.run(); }
private:
ba::io_service &io_service_;
};
void start_op(bad::operation* op)
{
start_work_thread();
io_service_impl_.work_started();
work_io_service_impl_.post_immediate_completion(op);
}
void start_work_thread()
{
bad::mutex::scoped_lock lock(mutex_);
if (!work_thread_.get())
{
work_thread_.reset(new bad::thread(
work_io_service_runner(*work_io_service_)));
}
}
bad::io_service_impl& io_service_impl_;
private:
bad::mutex mutex_;
boost::scoped_ptr<ba::io_service> work_io_service_;
bad::io_service_impl &work_io_service_impl_;
boost::scoped_ptr<ba::io_service::work> work_;
boost::scoped_ptr<bad::thread> work_thread_;
};
boost::asio::io_service::id basic_timer_service::id;
typedef basic_timer<basic_timer_service> timer;
void wait_handler(const boost::system::error_code &ec)
{
if(!ec)
std::cout << "wait_handler is called\n" ;
else
std::cerr << "Error: " << ec.message() << "\n";
}
int main()
{
{
boost::asio::io_service io_service;
boost::asio::signal_set signals(io_service);
timer t(io_service);
signals.add(SIGINT);
signals.async_wait(
boost::bind(&boost::asio::io_service::stop, &io_service));
t.async_wait(2, wait_handler);
std:: cout << "async called\n" ;
io_service.run();
std:: cout << "exit loop\n";
}
{
boost::asio::io_service io_service;
timer t(io_service);
t.async_wait(2, wait_handler);
std:: cout << "async called\n" ;
io_service.run();
}
return 0;
}
编译
gcc -I/boost_inc -L/boot_lib main.cpp -lpthread -lboost_system -lboost_thread
新计时器工作正常。我仍然想知道如何编写 asio 的非侵入式扩展。
关于c++ - boost::asio 的扩展被中断后挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13024711/
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
我想编写一个ruby脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"
这个问题有两个部分。在RubyProgrammingLanguage一书中,有一个使用模块扩展字符串对象和类的示例(第8.1.1节)。第一个问题。为什么如果您使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?irb(main):001:0>moduleGreeter;defciao;"Ciao!";end;end=>nilirb(main):002:0>String.extend(Greeter)=>Stringirb(main):003:0>String.ciao=>"Ciao!"irb(main):004:0>x="foobar"=>"foobar"irb(main):
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=