boost::asio asynchronous timer as an interrupt - c++

As I understand it, I should be able to use a boost:asio asynchronous timer to trigger a callback every n milliseconds whilst my program is doing something else without needing threads. Is that assumption correct ?
I put together the following test program which just prints the handler messages and never prints the rand() values. What I want is to see all the floating point numbers scroll down the screen, then every 250ms a handler message should appear in amongst them.
Here is the code :
#include <iostream>
#include <vector>
#include <cstdlib>
#include <boost/asio.hpp>
#include <boost/date_time.hpp>
#include <boost/thread.hpp>
boost::asio::io_service io_service;
boost::posix_time::time_duration interval(boost::posix_time::milliseconds(250));
boost::asio::deadline_timer timer(io_service,interval);
void handler(const boost::system::error_code& error);
void timer_init() {
timer.expires_at(timer.expires_at()+interval);
timer.async_wait(handler);
}
void handler(const boost::system::error_code& error) {
static long count=0;
std::cout << "in handler " << count++ << std::endl;
std::cout.flush();
timer_init();
}
int main(int argc, char **argv) {
timer.async_wait(handler);
io_service.run();
std::vector<double> vec;
for (long i=0; i<1000000000; i++) {
double x=std::rand();
std::cout << x << std::endl;
std::cout.flush();
vec.push_back(x);
}
return 0;
}

This:
io_service.run();
Is a blocking call. It's true that you can have multiple things happening asynchronously in one thread using ASIO, but you cannot have ASIO running in the same thread as code which is not integrated with ASIO. This is a classic event-driven model, where all the work gets done in response to some readiness notification (timers, in your case).
Try moving your vector/rand code to a function and passing that function to io_service::post(), which will then run that code within the context of its run() method. Then when you invoke run(), both things will happen (though not truly concurrently, as that would require threads).

As John Zwinck mentioned, io_service::run() blocks - it's a main asio loop that dispatches completion handlers. However, instead of calling run, you can "manually" process the io_service queue by interleaving io_service::poll_one with your loop:
for (long i=0; i<1000000000; i++) {
double x=std::rand();
std::cout << x << std::endl;
std::cout.flush();
vec.push_back(x);
io_service.poll_one();
}

Related

UDP Communication using Boost (for MATLAB s-function)

I'm trying to create an s-function (using C++ Boost library) for UDP communication.
Implementing the sender was fairly straightforward, 15 min job. I'm struggling to get the receiver to work.
I created the following in Visual Studio:
#define _WIN32_WINNT 0x0501
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <stdio.h>
typedef unsigned char UINT8;
typedef unsigned short UINT16;
using boost::asio::ip::udp;
using namespace std;
std::vector<char> receive_buffer;
void process_received_frame(const boost::system::error_code& error, size_t received_frame_size) {
if (error) {
cout << "Receive failed: " << error.message() << "\n";
return;
}
size_t ByteCount = 0;
std::cout << endl << "Received byte stream (Handler) [" << received_frame_size << "]: ";
for (std::vector<char>::const_iterator iter = receive_buffer.cbegin(); iter != receive_buffer.cend(); iter++)
{
ByteCount++;
printf("%02X ", (UINT8)*iter);
if (ByteCount == received_frame_size)
{
break;
}
}
std::cout << endl;
}
int main(int argc, char *argv[])
{
boost::asio::io_service io_service;
udp::socket socket(io_service);
udp::endpoint remote_endpoint = udp::endpoint(boost::asio::ip::address_v4::from_string("127.0.0.1"), 19001);
socket.open(udp::v4());
socket.bind(udp::endpoint(remote_endpoint));
receive_buffer.resize(255);
try
{
socket.async_receive_from(boost::asio::buffer(receive_buffer),
remote_endpoint,
boost::bind(&process_received_frame, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
catch (const std::exception& exp)
{
printf("%s\n", exp.what());
}
//io_service.poll();
io_service.run();
cout << "End";
std::cin.ignore();
}
I tried sending UDP to localhost:19001 from Simulink and was able to receive the UDP packets in Visual Studio. The handler (process_received_frame) gets called and everything seems to work, as expected.
But, given that, io_service::run() works in blocking mode, it pauses execution if there is nothing received on port 19001. So I tried using io_service::poll() (commented in the code above) instead. However, when I use poll(), it does not execute the handler. If I try to display the contents of 'receive_buffer' from main(), I get all 0s. Interestingly, when I single-step through the code for accessing the elements of 'receive_buffer' I do get the right values.
Not sure what is it that I'm doing wrong. Quite likely to be a school-boy-error.
When I convert this to an s-function for MATLAB-Simulink, it does the same thing - all zeros.
Any help would be much appreciated.
Cheers,
In your handler function, you need to call socket.async_receive_from at the end after processing the answer. io_service.run() returns when no more handler are in its processing queue.
See the example from boost doc here: udp sync server example
EDIT
Rereading your question/comment, I'm not sure what your expected output or behavior is.
If you're only expecting a single UDP frame, then maybe call io_service.run_one().
If you don't want run() to block your main thread, you need to launch another thread to call run(). Something like:
boost::asio::io_service io_service;
// Process handlers in a background thread.
boost::thread t(boost::bind(&io_service::run, &io_service));
...
io_service::run() is always a blocking call. Completion handlers can only be called from threads currently calling run(). The only time run() is going to return is when there is no more handlers in the queue (you stopped calling async_receive) or if you explicitly cancel the run() command by calling stop() or reset()

In boost::asio is it possible to have one deadline_timer with multiple execution times?

So I was experimenting with the deadline_timer class and wrote the code below to see if I could have on deadline_timer with multiple async_wait operations that would execute at different times.
Below I create a deadline timer in the main function all the way at the bottom and initially set it to expire after 3 seconds. Then I call an async_wait operation and pass the first print function as the handler. I then use the expires_from_now operation to set the time of expiration for what I intended to only affect the second async_wait call which has print2 as a handler. The output from running this is below the code.
This is test1.cpp
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/bind.hpp>
#include <time.h>
#include <sys/time.h>
double get_wall_time(){
struct timeval time;
if (gettimeofday(&time,NULL)){
// Handle error
return 0;
}
return (double)time.tv_sec + (double)time.tv_usec * .000001;
}
void print(double start, const boost::system::error_code& /*e*/)
{
std::cout << "Hello, world!" << std::endl;
std::cout << get_wall_time() - start << std::endl;
}
void print2(double start, const boost::system::error_code& /*e*/)
{
std::cout << "SECOND Hello, world!" << std::endl;
std::cout << get_wall_time() - start << std::endl;
}
int main(int argc, char* argv[])
{
boost::asio::io_service io;
boost::asio::deadline_timer timer(io, boost::posix_time::seconds(3));
auto start = get_wall_time();
timer.async_wait(boost::bind(print, start, boost::asio::placeholders::error));
timer.expires_from_now(boost::posix_time::seconds(20));
timer.async_wait(boost::bind(print2, start, boost::asio::placeholders::error));
io.run();
return 0;
}
Here is the output
Hello, world!
0.000774145
SECOND Hello, world!
20.0085
This is the output after commenting out the second async_wait with the expiration modification.
Hello, world!
3.00079
As you can see the first handler executes instantly when I intended for it to execute after 3 seconds. The second handler correctly executes after 20 seconds. Is there any way I could get the behavior I intended with a deadline_timer without having to create a bunch of them?
A timer must have only one outstanding async_wait at a time. IIRC, issuing another implicitly cancels the first one (which will fire it's handler with an error code) as if you called cancel() followed by async_wait().
If you want to respond to 2 timer events, you have 2 choices. Either have 2 timers, or set the timeout and issue the second async_wait in the handler of the first.

boos::asio async_wait seems to be blocking

I was learning boost asio documentation.I came across this deadline_timer example.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
/*This timer example shows a timer that fires once every second.*/
void print(const boost::system::error_code& e, boost::asio::deadline_timer* t, int* count)
{
if (*count < 5)
{
std::cout << *count << std::endl;
++(*count);
t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
t->async_wait(boost::bind(print,boost::asio::placeholders::error, t, count));
}
}
int main()
{
boost::asio::io_service io;
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
auto myfunc = boost::bind(print, boost::asio::placeholders::error, &t ,&count);
t.async_wait(myfunc);
std::cout << "async wait " << std::endl;
io.run();
std::cout << "Just called io.run() " << std::endl;
std::cout << "Final count is " << count << std::endl;
return 0;
}
The async_wait() function seems to be blocking (i.e waiting for the 10 second timer to expire)
The output from the above program is as follows.
async wait
0
1
2
3
4
Just called io.run()
Final count is 5
I would expect an async_wait() to create a separate thread and wait for the timer to expire there meanwhile executing the main thread.
i.e I would expect the program to print
Just called io.run()
Final count is 5
while waiting for the timer to expire.? Is my understanding wrong?
This is my understanding of async_wait(). This implementation looks more like a blocking wait. Is my understanding wrong? What am I missing?
The io.run(); statement is the key to explaining the difference between the output you're getting and the output you're expecting.
In the ASIO framework, any asynchronous commands need to have a dedicated thread to run the callbacks upon. But because ASIO is relatively low-level, it expects you to provide the thread yourself.
As a result, what you're doing when you call io.run(); within the main thread is to specify to the framework that you intend to run all asynchronous commands on the main thread. That's acceptable, but that also means that the program will block on io.run();.
If you intend the commands to run on a separate thread, you'll have to write something like this:
std::thread run_thread([&]() {
io.run();
});
std::cout << "Just called io.run() " << std::endl;
std::cout << "Final count is " << count << std::endl;
run_thread.join();
return 0;
The async_wait function isn't blocking, run is. That's run's job. If you don't want a thread to block in the io_service's processing loop, don't have that thread call run.
The async_wait function doesn't create any threads. That would make it expensive and make it much harder to control the number of threads servicing the io_service.
Your expectation is unreasonable because returning from main terminates the process. So who or what would wait for the timer?

boost::asio signal_set handler only executes after first signal is caught and ignores consecutive signals of the same type

I have a program and would like to stop it by sending SIGINT for writing some data to a file instead of exiting immediately. However, if the user of the program sends SIGINT again, then the program should quit immediately and forget about writing data to a file.
For portability reason I would like to use boost::asio for this purpose.
My initial (simplified) approach (see below) did not work. Is this not possible or am I missing something?
The handler seems to be called only once (printing out the message) and the program always stops when the loop has reached the max iteration number.
void handler(
const boost::system::error_code& error,
int signal_number) {
if (!error) {
static bool first = true;
if(first) {
std::cout << " A signal(SIGINT) occurred." << std::endl;
// do something like writing data to a file
first = false;
}
else {
std::cout << " A signal(SIGINT) occurred, exiting...." << std::endl;
exit(0);
}
}
}
int main() {
// Construct a signal set registered for process termination.
boost::asio::io_service io;
boost::asio::signal_set signals(io, SIGINT);
// Start an asynchronous wait for one of the signals to occur.
signals.async_wait(handler);
io.run();
size_t i;
for(i=0;i<std::numeric_limits<size_t>::max();++i){
// time stepping loop, do some computations
}
std::cout << i << std::endl;
return 0;
}
When your first event is handled, you don't post any new work on the service object, so it exits.
This means that then (after the ioservice exited) the tight loop is started. This may not be what you expected.
If you want to listen for SIGINT again, you have to wait for the signal set again from the handler:
#include <boost/asio.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/bind.hpp>
#include <boost/atomic.hpp>
#include <iostream>
void handler(boost::asio::signal_set& this_, boost::system::error_code error, int signal_number) {
if (!error) {
static boost::atomic_bool first(true);
if(first) {
// do something like writing data to a file
std::cout << " A signal(SIGINT) occurred." << std::endl;
first = false;
this_.async_wait(boost::bind(handler, boost::ref(this_), _1, _2));
}
else {
std::cout << " A second signal(SIGINT) occurred, exiting...." << std::endl;
exit(1);
}
}
}
int main() {
// Construct a signal set registered for process termination.
boost::asio::io_service io;
boost::asio::signal_set signals(io, SIGINT);
// Start an asynchronous wait for one of the signals to occur.
signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
io.run();
return 2;
}
As you can see I bound the signal_set& reference to the handler in order to be able to async_wait on it after receiving the first signal. Also, as a matter of principle, I made first an atomic (although that's not necessary until you run the io_service on multiple threads).
Did you actually wish to run the io_service in the background? In that case, make it look like so:
signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
boost::thread(boost::bind(&boost::asio::io_service::run, boost::ref(io))).detach();
while (true)
{
std::cout << "Some work on the main thread...\n";
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
With typical output:
Some work on the main thread...
Some work on the main thread...
Some work on the main thread...
^CSome work on the main thread...
A signal(SIGINT) occurred.
Some work on the main thread...
Some work on the main thread...
^CSome work on the main thread...
A second signal(SIGINT) occurred, exiting....

C++ Boost ASIO simple periodic timer?

I want a very simple periodic timer to call my code every 50ms. I could make a thread that sleeps for 50ms all the time (but that's a pain)... I could start looking into Linux API's for making timers (but it's not portable)...
I'd like to use boost.. I'm just not sure it's possible. Does boost provide this functionality?
A very simple, but fully functional example:
#include <iostream>
#include <boost/asio.hpp>
boost::asio::io_service io_service;
boost::posix_time::seconds interval(1); // 1 second
boost::asio::deadline_timer timer(io_service, interval);
void tick(const boost::system::error_code& /*e*/) {
std::cout << "tick" << std::endl;
// Reschedule the timer for 1 second in the future:
timer.expires_at(timer.expires_at() + interval);
// Posts the timer event
timer.async_wait(tick);
}
int main(void) {
// Schedule the timer for the first time:
timer.async_wait(tick);
// Enter IO loop. The timer will fire for the first time 1 second from now:
io_service.run();
return 0;
}
Notice that it is very important to call expires_at() to set a new expiration time, otherwise the timer will fire immediately because it's current due time already expired.
The second example on Boosts Asio tutorials explains it.
You can find it here.
After that, check the 3rd example to see how you can call it again with a periodic time intervall
To further expand on this simple example. It will block the execution as was said in the comments, so if you want more io_services running, you should run them in a thread like so...
boost::asio::io_service io_service;
boost::asio::io_service service2;
timer.async_wait(tick);
boost::thread_group threads;
threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
service2.run();
threads.join_all();
As I had some issues with prior answers, here is my example:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
void print(const boost::system::error_code&, boost::asio::deadline_timer* t,int* count)
{
if (*count < 5)
{
std::cout << *count << std::endl;
++(*count);
t->expires_from_now(boost::posix_time::seconds(1));
t->async_wait(boost::bind(print, boost::asio::placeholders::error, t, count));
}
}
int main()
{
boost::asio::io_service io;
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
t.async_wait(boost::bind(print, boost::asio::placeholders::error, &t, &count));
io.run();
std::cout << "Final count is " << count << std::endl;
return 0;
}
it did what it supposed to do: counting to five. May it help someone.
A Boost Asio add-on class that encapsulates this functionality (call a specfied function every N milliseconds): https://github.com/mikehaben69/boost/tree/main/asio
The repo includes a demo source file and makefile.