Re: [Cppcms-users] Synchronous app calls io_service.post() and blocks itself
Brought to you by:
artyom-beilis
|
From: Artyom B. <art...@ya...> - 2014-03-18 07:53:18
|
Hello,
Excellent question.
It is both correct and isn't correct, depends on what you do.
See my notes
> My understanding is that all requests
> sent to booster::aio::io_service
> are processed "sequentially", meaning that these requests
> must wait in
> line for service from the single instance of
> booster::aio::io_service.
> This characteristic of "processing requests one at a time"
> refrains
> requests from racing issue. Locking is not required in such
> use case
> when aio is used instead.
Yes
> This is why my synchronous application calls
> io_service.post() in order
> to ensure no racing:
>
> async_app->service().get_io_service().post(boost::bind(&my_class::my_method,this));
>
Now there is a slight problem...
(a) what is "this"
(b) what thread "this" lives in
if this is an async application living in the event-loop thread - no problem.
if it is some persistent class (not a sync app!!!) that is only accessed from the event loop, it is ok as well.
this is a synchronous app that it isn't correct (in most of cases) because:
1. the synchronous application "lives" in the thread pool so the my_method would be called from a different thread (event-loop thread)
2. the synchronous application may not even exist when my_method is called because it was removed from the application cache
So it is better to pass the relevant data to the async_app withing the callback, i,e,
struct mydata {
// all data needed
void operator()() const // the callback
{
async_app->handle(this);
}
};
mydata info_for_async_thread;
async_app->service().get_io_service().post(info_for_async_thread);
> Now I want this synchronous application not to respond to
> clients and
> return immediately. Instead, this synchronous application
> will wait
> until my_class::my_method completes before it continues.
> Is such design correct? If it is, how do I implement this?
> If it is not,
> what alternatives do I have?
Now the case when you actually make the sync app to wait for the response...
technically you can implement this by for example waiting for a conditional variable.
that would be changed in the event loop:
Caller
------------------
this->resp_is_ready=false
async_app->service().get_io_service().post(boost::bind(&my_class::my_method,this));
while(true){
booster::unique_lock guard(this->resp_is_ready_mutex)
this->resp_is_ready_cond.wait(guard)
if(this->resp_is_ready)
break;
}
-------------
Handler
---------------------
my_class:my_method()
{
// do something with async app/withing the event loop
booster::unique_lock guard(this->resp_is_ready_mutex);
this->resp_is_ready = true
this->resp_is_ready_cond.notify_one()
}
--------------------------------------------------------
Now the question what do you need this for...
If you need to do a fast query from the event loop for some data without running too many mutexes
it is ok. However it is still somewhat borderline. I'd suggest to keep some data in some global object
with very short and fast accesses protected by mutexes.
But... if you want to put the thread on hold for a long time (for example to wait for some other event),
it is very bad idea as you may run out of threads in the pool very fast.
If you want to postpone the response of the synchronous application you may do the following steps:
(a) detach the http::context (like in async app)
(b) change the response().io_mode() to asynchronous
(c) send the detached http::context to the async_app to handle it asynchronously vio post()...
So basically sync app tells I don't want to handle it and give it away to the async app.
(this probably should go to wiki :-) )
Artyom Beilis
--------------
CppCMS - C++ Web Framework: http://cppcms.com/
CppDB - C++ SQL Connectivity: http://cppcms.com/sql/cppdb/
|