Hello all, I am new to boost and asio in particular. For now I am implementing a simple UDP sender. The sending process itself works fine but for some reason the send handler does not execute. The call itself looks like this: In my class sender.cpp I have a functions called void sender::sendIt(){ sj->dFC->s->async_send_to(boost::asio::buffer( this->charBuffer,sendBytes), *sj->dFC->e, boost::bind(&sender::sendHandler,this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred); } and the corresponding handler is this: void sender::sendHandler(const boost::system::error_code& error,std::size_t bytes_transferred){ cout << "TRIGGER" << endl; } Can anyone give me a hint what the reason for the not-working handler might be ? Thanks in advance, best Alex
I am new to boost and asio in particular. For now I am implementing a simple UDP sender.
The sending process itself works fine but for some reason the send
handler does not execute.
Most likely, io_service::run() isn't running.
I see - yes, this is very likely indeed. In that context more questions: Simply calling run in my case doesn't help: sj->dFC->io_service.run(); So I saw a number of examples, in which an extra thread is created via: boost::thread t = boost::thread (boost::bind(&boost::asio::io_service::run, &sj->dFC->io_service)); t.join(); This didn't change anything either. Is it correct to create an explicit thread ? If so does my base-class (which contains the async_functions) have to inherit this thread in order to make it work ? At the moment I simply create it within the class. Thanks in advance, best Alex
I am new to boost and asio in particular. For now I am implementing a simple UDP sender.
The sending process itself works fine but for some reason the send
handler does not execute.
Most likely, io_service::run() isn't running.
I see - yes, this is very likely indeed. In that context more questions:
Simply calling run in my case doesn't help: sj->dFC->io_service.run();
So I saw a number of examples, in which an extra thread is created via:
boost::thread t = boost::thread (boost::bind(&boost::asio::io_service::run, &sj->dFC->io_service)); t.join();
This didn't change anything either.
Is it correct to create an explicit thread ? If so does my base-class (which contains the async_functions) have to inherit this thread in order to make it work ? At the moment I simply create it within the class.
You can create an explicit thread an invoke io_service::run() there, as you've shown above. No need to inherit thread, boost::thread/std::thread object accepts the thread procedure as a parameter. In general, it's quite hard to tell what the problem is without seeing your code. If you can't make a small self-contained sample that reproduces the issue, try posting your real code.
You can create an explicit thread an invoke io_service::run() there, as you've shown above. No need to inherit thread, boost::thread/std::thread object accepts the thread procedure as a parameter. In general, it's quite hard to tell what the problem is without seeing your code. If you can't make a small self-contained sample that reproduces the issue, try posting your real code.
Sure ! In fact the existing code is quite complex. It is an existing Qt-based project of mine, in which I currently replace Qt with boost. First will need to extract the relevant parts before I will get back to you. Thanks a lot for you help so far, best Alex
You can create an explicit thread an invoke io_service::run() there, as you've shown above. No need to inherit thread, boost::thread/std::thread object accepts the thread procedure as a parameter. In general, it's quite hard to tell what the problem is without seeing your code. If you can't make a small self-contained sample that reproduces the issue, try posting your real code.
Sure ! In fact the existing code is quite complex. It is an existing Qt-based project of mine, in which I currently replace Qt with boost. First will need to extract the relevant parts before I will get back to you.
Anyway, if handlers do not get invoked it usually means that io_service::run() loop either doesn't run or is eternally blocked by some other completion handler. The former case can occur, for example, if io_service runs out work, i.e. run() just exits (note that is you call io_service::run() when there's no async.operation in progress and it has no associated io_serivce::work, the io_service runs out of work immediately). The both cases are relatively easy to debug.
You can create an explicit thread an invoke io_service::run() there, as you've shown above. No need to inherit thread, boost::thread/std::thread object accepts the thread procedure as a parameter. In general, it's quite hard to tell what the problem is without seeing your code. If you can't make a small self-contained sample that reproduces the issue, try posting your real code.
Allright -- I tried to simplify things as much as possible. My app is a music live music streamer, which sends and receives UDP audio data. I will start with the sender first. Please note that any network related data (io_service, endpoint, socket etc.) is all defined within a struct called dFC, which belongs to a class called sj - hence I address them via sj->dFC->... I have an audio callback thread, which sends a UDP packet in a time interval of 10.8 ms: -------------- static int callback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,void *data ){ sj::callbackdata *my; my = (sj::callbackdata *) data; ///SENDER if (my->streaming) my->mySender->sendIt(buffer); ///FURTHER STUFF WITHOUT RELEVANCE FOR NOW ... } -------------
From this function I call the class mySender, which contains the async_send command and the handler:
------------ void sender::sendHandler(const boost::system::error_code& error,std::size_t bytes_transferred){ cout << "TRIGGER !" << endl; } void sender::sendIt(char *charBuffer){ cout << "SENDING" << endl; sj->dFC->s->async_send_to(boost::asio::buffer(charBuffer, sj->dFC->sendBytes), *sj->dFC->e, boost::bind(&sender::sendHandler,this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); sj->dFC->io_service.run(); } ----------------- The good news are that it works - the bad news are: It works only once so that the console output looks like this: SENDING TRIGGER SENDING SENDING SENDING SENDING SENDING SENDING ... I believe I am not using the io_service correctly. Can you help ? Thanks Alex
On 12/16/2013 06:51 PM, Alexander Carôt wrote:
void sender::sendIt(char *charBuffer){ [...] sj->dFC->io_service.run();
You should not call io_service::run() inside this function. The normal pattern is to set up your network code, e.g. from main(), and then call run() after setup. This call will block (and all Asio callbacks will be executed from this thread.) If you do not want your main thread to handle the network code, then you can launch in a separate thread (as previously suggested.)
void sender::sendIt(char *charBuffer){ [...] sj->dFC->io_service.run();
You should not call io_service::run() inside this function. The normal pattern is to set up your network code, e.g. from main(), and then call run() after setup. This call will block (and all Asio callbacks will be executed from this thread.) If you do not want your main thread to handle the network code, then you can launch in a separate thread (as previously suggested.)
Yes, I truly understand this but for some weired reason this doesn't work at all. In my case I launch the run function in the constructor of the main class right after the sender class had been instantiated: SJ::SJ(){ /// SENDER INIT dFC->mySender = new sender(this); boost::thread t = boost::thread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); t.join(); // OR dFC->io_service.run(); } In there anything wrong with this ? Thanks Alex
void sender::sendIt(char *charBuffer){ [...] sj->dFC->io_service.run();
You should not call io_service::run() inside this function. The normal pattern is to set up your network code, e.g. from main(), and then call run() after setup. This call will block (and all Asio callbacks will be executed from this thread.) If you do not want your main thread to handle the network code, then you can launch in a separate thread (as previously suggested.)
Yes, I truly understand this but for some weired reason this doesn't work at all. In my case I launch the run function in the constructor of the main class right after the sender class had been instantiated: SJ::SJ(){ /// SENDER INIT dFC->mySender = new sender(this); boost::thread t = boost::thread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); t.join(); // OR dFC->io_service.run(); } In there anything wrong with this ? Thanks Alex
P.S.: This is a way simpler program, which behaves in the same way: When
launching the thread before the async_send call it does not work - when
launching it after it does:
/* async_send_to udp example
* compile with
* g++ -o udpserver2 udpserver2.cpp -lboost_system -lboost_signals
-lboost_thread
*/
#include <iostream>
#include
void sender::sendIt(char *charBuffer){ [...] sj->dFC->io_service.run();
You should not call io_service::run() inside this function. The normal pattern is to set up your network code, e.g. from main(), and then call run() after setup. This call will block (and all Asio callbacks will be executed from this thread.) If you do not want your main thread to handle the network code, then you can launch in a separate thread (as previously suggested.)
Yes, I truly understand this but for some weired reason this doesn't work at all. In my case I launch the run function in the constructor of the main class right after the sender class had been instantiated:
SJ::SJ(){
/// SENDER INIT dFC->mySender = new sender(this);
boost::thread t = boost::thread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); t.join();
// OR dFC->io_service.run(); }
In there anything wrong with this ?
Thanks
Alex
Yes, I truly understand this but for some weired reason this doesn't work at all. In my case I launch the run function in the constructor of the main class right after the sender class had been instantiated:
SJ::SJ(){
/// SENDER INIT dFC->mySender = new sender(this);
boost::thread t = boost::thread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); t.join();
// OR dFC->io_service.run(); }
In there anything wrong with this ?
It seems that you call io_serivce::run() before any async operation was issued. In such a case, run() just exits immediately, as I explained in one of my previous comments. In order to avoid such a behavior, associate io_service::work object with this io_service: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_servic... (scroll down) In general, it's highly recommended to read the Asio documentation - all these issues are described there.
Yes, I truly understand this but for some weired reason this doesn't work at all. In my case I launch the run function in the constructor of the main class right after the sender class had been instantiated:
SJ::SJ(){
/// SENDER INIT dFC->mySender = new sender(this);
boost::thread t = boost::thread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); t.join();
// OR dFC->io_service.run(); }
In there anything wrong with this ?
It seems that you call io_serivce::run() before any async operation was issued. In such a case, run() just exits immediately, as I explained in one of my previous comments. In order to avoid such a behavior, associate io_service::work object with this io_service: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_serv ice.html
Allright - this helps but still issues (see below).
In general, it's highly recommended to read the Asio documentation - all these issues are described there.
Yes, you can assume this but it seems the case is a little more complex than it is the case with the default use cases: This simple example works fine: ---------------------------- boost::asio::io_service io_service; int i = 0; void handle_send(const boost::system::error_code& error, std::size_t bytes_transferred){ i++; std::cout << "async_send_to return " << error << ": " << bytes_transferred << " transmitted " << i << std::endl; } int main(int argc, char *argv[]){ if(argc==3){ boost::asio::io_service::work work(io_service); boost::thread t = boost::thread (boost::bind(&boost::asio::io_service::run, &io_service)); //t.join(); boost::asio::ip::udp::socket socket(io_service); boost::asio::ip::udp::endpoint remote_endpoint; socket.open(boost::asio::ip::udp::v4()); remote_endpoint = boost::asio::ip::udp::endpoint( boost::asio::ip::address::from_string(argv[1]), boost::lexical_cast<int>(argv[2])); std::cout << "Send to " << remote_endpoint << std::endl; while (1) socket.async_send_to(boost::asio::buffer("message", 7), remote_endpoint, boost::bind(&handle_send, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); return 0; } ----------------------------- but with respect to my app this does not work: I am specifying the io_service thread in my constructor. SJ::SJ(){ boost::asio::io_service::work work(dFC->io_service); boost::thread myThread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); } I have a handle in my custom SJ class: void SJ::handleSend(const boost::system::error_code& error, std::size_t bytes_transferred){ cout << "SENT FROM HANDLER" << endl; } I have a send function: void SJ::sendIt(){ cout << "Send Funktion" << endl; dFC->s->async_send_to(boost::asio::buffer("message", 7), remote_endpoint, boost::bind(&handleSender, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } The send function is called from an *non-class-member* callback thread (my->sj->sendIt()): static int audioCallback( void *data ){ SJ::callbackdata *my; my = (SJ::callbackdata *) data; my->sj->sendIt(); } Not that everything works fine when I call the send function from within my SJ-class but when I call the send function from the external callback thread the handler is not triggering anymore. Does this help to clarify what (or where) my problem is ? Thanks again Alex
Yes, I truly understand this but for some weired reason this doesn't work at all. In my case I launch the run function in the constructor of the main class right after the sender class had been instantiated:
SJ::SJ(){
/// SENDER INIT dFC->mySender = new sender(this);
boost::thread t = boost::thread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); t.join();
// OR dFC->io_service.run(); }
In there anything wrong with this ?
It seems that you call io_serivce::run() before any async operation was issued. In such a case, run() just exits immediately, as I explained in one of my previous comments. In order to avoid such a behavior, associate io_service::work object with this io_service:
http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_serv
ice.html
Allright - this helps but still issues (see below).
In general, it's highly recommended to read the Asio documentation - all these issues are described there.
Yes, you can assume this but it seems the case is a little more complex than it is the case with the default use cases:
This simple example works fine:
---------------------------- boost::asio::io_service io_service;
int i = 0;
void handle_send(const boost::system::error_code& error, std::size_t bytes_transferred){ i++; std::cout << "async_send_to return " << error << ": " << bytes_transferred << " transmitted " << i << std::endl; }
int main(int argc, char *argv[]){ if(argc==3){
boost::asio::io_service::work work(io_service); boost::thread t = boost::thread (boost::bind(&boost::asio::io_service::run, &io_service)); //t.join();
boost::asio::ip::udp::socket socket(io_service); boost::asio::ip::udp::endpoint remote_endpoint;
socket.open(boost::asio::ip::udp::v4());
remote_endpoint = boost::asio::ip::udp::endpoint( boost::asio::ip::address::from_string(argv[1]), boost::lexical_cast<int>(argv[2]));
std::cout << "Send to " << remote_endpoint << std::endl;
while (1) socket.async_send_to(boost::asio::buffer("message", 7), remote_endpoint, boost::bind(&handle_send, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
return 0; } -----------------------------
but with respect to my app this does not work:
I am specifying the io_service thread in my constructor.
SJ::SJ(){ boost::asio::io_service::work work(dFC->io_service); boost::thread myThread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); }
I have a handle in my custom SJ class:
void SJ::handleSend(const boost::system::error_code& error, std::size_t bytes_transferred){ cout << "SENT FROM HANDLER" << endl; }
I have a send function:
void SJ::sendIt(){ cout << "Send Funktion" << endl;
dFC->s->async_send_to(boost::asio::buffer("message", 7), remote_endpoint, boost::bind(&handleSender, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); }
The send function is called from an *non-class-member* callback thread (my->sj->sendIt()):
static int audioCallback( void *data ){ SJ::callbackdata *my; my = (SJ::callbackdata *) data;
my->sj->sendIt(); }
Not that everything works fine when I call the send function from within my SJ-class but when I call the send function from the external callback thread the handler is not triggering anymore.
Does this help to clarify what (or where) my problem is ?
Thanks again
Alex
Isn't this caused because boost::asio::io_service::work is a local variable to the constructor, so when the constructor is done, work is destructed, and nothing is left to keep io_service.run() from returning.
On 12/17/2013 04:54 PM, Alexander Carôt wrote:
SJ::SJ(){ boost::asio::io_service::work work(dFC->io_service); boost::thread myThread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); }
The work object is destroyed when execution leaves the constructor, and the work destructor signals to the io_service that the work is complete. Try making work a member variable instead.
Thanks a lot to Aaron, Bjorn and Igor for you constructive comments !
Finally it works fine even in the environment of my former Qt-based
project. In fact some problems (especially the last on with the local work
variable in the constructor) might have sounded trivial but I tend to
become confused when switching to a new technology. Be prepared for more
issues to come ;-)
Best regards
Alex
Am 17.12.13 17:30 schrieb "Bjorn Reese" unter
On 12/17/2013 04:54 PM, Alexander Carôt wrote:
SJ::SJ(){ boost::asio::io_service::work work(dFC->io_service); boost::thread myThread(boost::bind(&boost::asio::io_service::run, &dFC->io_service)); }
The work object is destroyed when execution leaves the constructor, and the work destructor signals to the io_service that the work is complete.
Try making work a member variable instead.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-------------- static int callback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,void *data ){ <...> if (my->streaming) my->mySender->sendIt(buffer);
<...>
void sender::sendIt(char *charBuffer){ <...> sj->dFC->s->async_send_to(boost::asio::buffer(charBuffer, sj->dFC->sendBytes), *sj->dFC->e, boost::bind(&sender::sendHandler,this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); sj->dFC->io_service.run(); } -----------------
The good news are that it works - the bad news are: It works only once
It looks like you call io_service::run() "ad hoc", just to process the handler of the previous async_send_to (note that it blocks until this handler is dispatched), so every time you call async_send_to - you call io_service::run() again. Thus, you have to call io_service::reset() prior to any subsequent call to run(): http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_servic... But please note that this is untypical usage of io_service -- you actually simulate a blocking, synchronous operation.
participants (5)
-
"Alexander Carôt"
-
Aaron_Wright@selinc.com
-
Alexander Carôt
-
Bjorn Reese
-
Igor R