使用ctrl+c中断阻塞系统调用



下面是我正在使用的代码的精简示例:

void SleepIntr()
{
    printf("Entering sleep...n");
    SleepEx(10000, TRUE);
    printf("Sleep done...n");
}
static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) {
    printf("ctrl_handler pressedn");
    // Wake program up!
    return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
    SetConsoleCtrlHandler(ctrl_handler, TRUE);
    SleepIntr();
    printf("awake!n"); 
    return 0;
}

这个想法是当按下ctrl +c时,睡眠应该被中断,程序应该继续执行并打印"awake!"或者至少给我一个堆栈跟踪,当按下ctrl+c时,执行在哪里。

SleepEx调用可以是任何阻塞的系统调用,例如从套接字阻塞读取。

我应该在我的ctrl_handler中写什么来中断呼叫?除了终止整个过程,我什么也没找到。如果不可能,我就接受这个答案,但我真的很想知道为什么。

下面是Linux上的等效程序编码,使用nanosleep代替SleepEx:

#include <signal.h>
#include <stdio.h>
#include <time.h>
void ctrl_c (int sid, siginfo_t *info, void *data) {
    printf("Im a ctrl_cn");
}
int main (int argc, char *argv[]) {
    struct sigaction act = {0};
    act.sa_sigaction = &ctrl_c;
    sigaction(SIGINT, &act, NULL);
    struct timespec t, t2;
    t.tv_sec = 5;
    t.tv_nsec = 0;
    printf("sleep startn");
    nanosleep (&t, &t2);
    printf("sleep endn");
    return 0;
}

它完全像我想要的那样工作。在nanosleep中的Ctrl+c会立即中断它,并通过打印"sleep end"继续执行。为什么类似的东西不能在Windows上为sleeppex工作?

EDIT SleepEx的第二个参数当然应该是TRUE。这是个打字错误

你需要知道你打断了什么,并且代码必须被设计成可以被打断,这是无法回避的事实。

在您选择的特定示例中,将睡眠替换为对事件的定时等待。你可以通过设置事件来中断它。

如果你正在进行一个同步I/O调用,你可以使用CancelSynchronousIo,但是当然处理I/O的代码必须正确地处理取消。

如果你在alertable wait中,你可以把APC排队给线程。

如果你在一个消息循环中,你可以发布消息或让循环使用MsgWaitForMultipleObjectsEx

附加: 演示如何唤醒SleepEx

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
HANDLE mainthread;
VOID CALLBACK DummyAPCProc(
  _In_  ULONG_PTR dwParam
)
{
    printf("User APCn");
    return;
}
void SleepIntr()
{
    printf("Entering sleep...n");
    SleepEx(10000, TRUE);
    printf("Sleep done...n");
}
static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) {
    printf("ctrl_handler pressedn");
    // Wake program up!
    if (!QueueUserAPC(DummyAPCProc, mainthread, NULL))
    {
        printf("QueueUserAPC: %un", GetLastError());
        return TRUE;
    }
    return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
    if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainthread, GENERIC_ALL, FALSE, 0))
    {
        printf("DuplicateHandle: %un", GetLastError());
        return 0;
    }
    SetConsoleCtrlHandler(ctrl_handler, TRUE);
    SleepIntr();
    printf("awake!n"); 
    return 0;
}   

最新更新