The C++ class CtrlCHandler provides a portable abstraction to handle CTRL-C and similar signals sent to a C++ process. On Windows, CtrlCHandler is a wrapper for SetConsoleCtrlHandler; on POSIX platforms, it handles SIGHUP, SIGTERM and SIGINT with a dedicated thread that waits for these signals using sigwait. Signals are handled by a callback function that you implement and register. The callback is a simple function that takes an int (the signal number) and returns void; it must not throw any exception:

namespace Ice
{
    class CtrlCHandler
    {
    public:
        explicit CtrlCHandler(std::function<void(int)> = nullptr);
        ~CtrlCHandler();

        std::function<void(int)> setCallback(std::function<void(int>));
        std::function<void(int)> getCallback() const;
    };
}
namespace Ice
{
    typedef void (*CtrlCHandlerCallback)(int);

    class CtrlCHandler
    {
    public:
        explicit CtrlCHandler(CtrlCHandlerCallback = 0);
        ~CtrlCHandler();

        CtrlCHandlerCallback setCallback(CtrlCHandlerCallback);
        CtrlCHandlerCallback getCallback() const;
    };
}

 

The member functions of CtrlCHandler behave as follows:

It is legal specify nullptr for the callback function, in which case signals are caught and ignored until a non-null callback function is set.

A typical use for CtrlCHandler is to shutdown a communicator in an Ice server. For example, you could use it as follows:

int
main(int argc, char* argv[])
{
    Ice::CtrlCHandler ctrlCHandler;
    try
    {
        Ice::CommunicatorHolder ich(argc, argv);
        ctrlCHandler.setCallback([communicator = ich.communicator()](int signal) // C++14 syntax
                                 {
                                     cerr << "caught signal " << signal << ", shutting down communicator" << endl;
                                     try
                                     {
                                         communicator->shutdown();
                                     }
                                     catch(const Ice::CommunicatorDestroyedException&)
                                     {
                                         // ignored
                                     }
                                 });
        auto adapter =
            ich->createObjectAdapterWithEndpoints("Hello", "default -h localhost -p 10000");
        adapter->add(make_shared<HelloI>(), Ice::stringToIdentity("hello"));
        adapter->activate();
        ich->waitForShutdown();
    }
    catch(const std::exception& ex)
    {
        cerr << ex.what() << endl;
        return 1;
    }
    return 0;
} 
Ice::CommunicatorPtr communicator;
void shutdownCommunicator(int);

int
main(int argc, char* argv[])
{
    Ice::CtrlCHandler ctrlCHandler;
    try
    {
        Ice::CommunicatorHolder ich(argc, argv);
        communicator = ich.communicator();
        ctrlCHandler.setCallback(shutdownCommunicator);

        Ice::ObjectAdapterPtr adapter =
            ich->createObjectAdapterWithEndpoints("Hello", "default -h localhost -p 10000");
        adapter->add(new HelloI, Ice::stringToIdentity("hello"));
        adapter->activate();
        ich->waitForShutdown();
    }
    catch(const std::exception& ex)
    {
        cerr << ex.what() << endl;
        return 1;
    }
    return 0;
}

void
shutdownCommunicator(int signal)
{
    cerr << "caught signal " << signal << ", shutting down communicator" << endl;
    try
    {
        communicator->shutdown();
    }
    catch(const Ice::CommunicatorDestroyedException&)
    {
        // ignored
    }
}

See Also