gpt4 book ai didi

c++ - 如何使用 Qt 在 Windows 和 Linux 上捕获 Ctrl+C

转载 作者:IT王子 更新时间:2023-10-29 00:04:14 26 4
gpt4 key购买 nike

我有 Qt 控制台服务器应用程序。我希望有人按 Ctrl+C 正确退出我的服务器(调用析构函数等)。我读过 this ,但是我希望它能在 Linux 和 Windows 上运行。怎么做?

最佳答案

我使用此类来捕获 C++ 控制台应用程序中的信号。然而,它并不特定于 Qt。它在 Windows 平台上使用 SetConsoleCtrlHandler(),在其他平台上使用 提供的功能。棘手的一点是“信号”不是跨平台术语——Windows 和 POSIX 对它们有不同的定义。无论如何,本类(class)试图将它们映射到一个共同的词汇表。 Ctrl^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);
}

信号处理器.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;
};

信号处理器.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

关于c++ - 如何使用 Qt 在 Windows 和 Linux 上捕获 Ctrl+C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7581343/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com