解决方法
我使用这个类在C控制台应用程序中捕获信号.不过Qt并不具体.它在Windows平台上使用SetConsoleCtrlHandler(),并由< signal.h>在其他平台上棘手的一点是,“信号”不是跨平台术语 – Windows和POSIX对它们有不同的定义.无论如何,这个类试图将它们映射到一个常见的词汇. Ctrl ^ C是在两个平台上映射良好的C ^ C.
我希望这可以适应你的具体情况.请注意,错误检查很小,应该可以改进.
用法(main.cpp)
#include "SignalHandler.h" class Application : public SignalHandler { public: Application() : SignalHandler(SignalHandler::SIG_INT),myThread(NULL) {} int Application::main(int argc,char *argv[]) { // Main program instructions here (e.g. start a thread) myThread = new Thread(...); myThread->start(); myThread->join(); delete myThread; return 0; } bool handleSignal(int signal) { std::cout << "Handling signal " << signal << std::endl; if (_myThread && _myThread->isRunning()) { _myThread->stop(); // The thread is going to stop soon,so don't propagate this signal further return true; } // Let the signal propagate as though we had not been there return false; } private: Thread* myThread; }; int main(int argc,char* argv[]) { Application app; return app.main(argc,argv); }
SignalHandler.h
class SignalHandler { public: SignalHandler(int mask = DEFAULT_SIGNALS); virtual ~SignalHandler(); enum SIGNALS { SIG_UNHANDLED = 0,// Physical signal not supported by this class SIG_NOOP = 1,// The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway) SIG_INT = 2,// Control+C (should terminate but consider that it's a normal way to do so; can delay a bit) SIG_TERM = 4,// Control+Break (should terminate now without regarding the consquences) SIG_CLOSE = 8,// Container window closed (should perform normal termination,like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM] SIG_RELOAD = 16,// Reload the configuration [Linux only,physical signal is SIGHUP; on Windows it maps to SIG_NOOP] DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE,}; static const int numSignals = 6; virtual bool handleSignal(int signal) = 0; private: int _mask; };
SignalHandler.cpp
#include "SignalHandler.h" #include <assert.h> #ifndef _WIN32 #include <signal.h> #else #include <windows.h> #endif //!_WIN32 // There can be only ONE SignalHandler per process SignalHandler* g_handler(NULL); #ifdef _WIN32 BOOL WINAPI WIN32_handleFunc(DWORD); int WIN32_physicalToLogical(DWORD); DWORD WIN32_logicalToPhysical(int); std::set<int> g_registry; #else //_WIN32 void POSIX_handleFunc(int); int POSIX_physicalToLogical(int); int POSIX_logicalToPhysical(int); #endif //_WIN32 SignalHandler::SignalHandler(int mask) : _mask(mask) { assert(g_handler == NULL); g_handler = this; #ifdef _WIN32 SetConsoleCtrlHandler(WIN32_handleFunc,TRUE); #endif //_WIN32 for (int i=0;i<numSignals;i++) { int logical = 0x1 << i; if (_mask & logical) { #ifdef _WIN32 g_registry.insert(logical); #else int sig = POSIX_logicalToPhysical(logical); bool Failed = signal(sig,POSIX_handleFunc) == SIG_ERR; assert(!Failed); (void)Failed; // Silence the warning in non _DEBUG; TODO: something better #endif //_WIN32 } } } SignalHandler::~SignalHandler() { #ifdef _WIN32 SetConsoleCtrlHandler(WIN32_handleFunc,FALSE); #else for (int i=0;i<numSignals;i++) { int logical = 0x1 << i; if (_mask & logical) { signal(POSIX_logicalToPhysical(logical),SIG_DFL); } } #endif //_WIN32 } #ifdef _WIN32 DWORD WIN32_logicalToPhysical(int signal) { switch (signal) { case SignalHandler::SIG_INT: return CTRL_C_EVENT; case SignalHandler::SIG_TERM: return CTRL_BREAK_EVENT; case SignalHandler::SIG_CLOSE: return CTRL_CLOSE_EVENT; default: return ~(unsigned int)0; // SIG_ERR = -1 } } #else int POSIX_logicalToPhysical(int signal) { switch (signal) { case SignalHandler::SIG_INT: return SIGINT; case SignalHandler::SIG_TERM: return SIGTERM; // In case the client asks for a SIG_CLOSE handler,accept and // bind it to a SIGTERM. Anyway the signal will never be raised case SignalHandler::SIG_CLOSE: return SIGTERM; case SignalHandler::SIG_RELOAD: return SIGHUP; default: return -1; // SIG_ERR = -1 } } #endif //_WIN32 #ifdef _WIN32 int WIN32_physicalToLogical(DWORD signal) { switch (signal) { case CTRL_C_EVENT: return SignalHandler::SIG_INT; case CTRL_BREAK_EVENT: return SignalHandler::SIG_TERM; case CTRL_CLOSE_EVENT: return SignalHandler::SIG_CLOSE; default: return SignalHandler::SIG_UNHANDLED; } } #else int POSIX_physicalToLogical(int signal) { switch (signal) { case SIGINT: return SignalHandler::SIG_INT; case SIGTERM: return SignalHandler::SIG_TERM; case SIGHUP: return SignalHandler::SIG_RELOAD; default: return SignalHandler::SIG_UNHANDLED; } } #endif //_WIN32 #ifdef _WIN32 BOOL WINAPI WIN32_handleFunc(DWORD signal) { if (g_handler) { int signo = WIN32_physicalToLogical(signal); // The std::set is thread-safe in const reading access and we never // write to it after the program has started so we don't need to // protect this search by a mutex std::set<int>::const_iterator found = g_registry.find(signo); if (signo != -1 && found != g_registry.end()) { return g_handler->handleSignal(signo) ? TRUE : FALSE; } else { return FALSE; } } else { return FALSE; } } #else void POSIX_handleFunc(int signal) { if (g_handler) { int signo = POSIX_physicalToLogical(signal); g_handler->handleSignal(signo); } } #endif //_WIN32