Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using boost asio to Catch Ctrl-C

I'm trying to catch the Ctrl-C in application as demonstrated in the following MWE

#include <boost/asio/signal_set.hpp>
#include <iostream>

void handler( const boost::system::error_code& error , int signal_number )
{
    std::cout << "handling signal " << signal_number << std::endl;
}

int main( int argc , char** argv )
{
    boost::asio::io_service io_service;

    // Construct a signal set registered for process termination.
    boost::asio::signal_set signals(io_service, SIGINT );

    // Start an asynchronous wait for one of the signals to occur.
    signals.async_wait( handler );

    char choice;
    while( true )
    {
        std::cout << "Press a key: " << std::endl;
        std::cin >> choice; 
    }
}

Unfortunately handler() is not called when I press Ctrl+C. On the contrary the loop no longer waits for user input as shown below:

c:\tmp>CtrlC.exe
Press a key:
d
Press a key:
e
Press a key:
Press a key:
Press a key:
Press a key:
Press a key:
Press a key:
Press a key:
Press a key:
Press a key:

If it matters, I'm on Windows and I know that there is a Windows specific way to catch Ctrl+C but I'd like to use boost if possible for ease of porting.

like image 994
Olumide Avatar asked Feb 06 '23 01:02

Olumide


2 Answers

boost ASIO in centered on the io_service object, all the tasks you request (especially the async ones) are usually handled by the io_service.

By doing:

// Start an asynchronous wait for one of the signals to occur.
signals.async_wait( handler );

You require the service to wait on the signals asynchronously and call your handler when it happens.

The thing is, your io_service is not running.

So if you want it to work correctly you need to start it:

#include <boost/asio/signal_set.hpp>
#include <iostream>

void handler( const boost::system::error_code& error , int signal_number )
{
  std::cout << "handling signal " << signal_number << std::endl;
  exit(1);
}

int main( int argc , char** argv )
{
  boost::asio::io_service io_service;

  // Construct a signal set registered for process termination.
  boost::asio::signal_set signals(io_service, SIGINT );

  // Start an asynchronous wait for one of the signals to occur.
  signals.async_wait( handler );

  io_service.run();
}

Then pressing Ctrl + C will do what you expect.

Note that the io_service basically replaces your infinite loop, so anything you would have done inside of it should become tasks for the io_service.

like image 149
Drax Avatar answered Feb 07 '23 14:02

Drax


You need to let io_service execute the handlers that has been passed to it. io_service can don that only if you call run or run_one methods of it. You can make use of the run_one method inside your while loop:

#include <boost/asio/signal_set.hpp>
#include <iostream>
#include <cstdlib>
#include <limits>

void handler( const boost::system::error_code& error , int signal_number )
{
    // Not safe to use stream here...
    std::cout << "handling signal " << signal_number << std::endl;
    exit (1);
}

int main( int argc , char** argv )
{
    boost::asio::io_service io_service;

    // Construct a signal set registered for process termination.
    boost::asio::signal_set signals(io_service, SIGINT );

    // Start an asynchronous wait for one of the signals to occur.
    signals.async_wait( handler );

    char choice;
    while( true )
    {
        std::cout << "Press a key: " << std::endl;
        std::cin >> choice;
        io_service.run_one();
    }
}
like image 23
Arunmu Avatar answered Feb 07 '23 14:02

Arunmu