0

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

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

这个想法是当按下 ctr+c 时,睡眠应该被中断,程序应该继续执行并打印“唤醒!” 或者至少给我一个堆栈跟踪,了解按下 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_c\n");
}
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 start\n");
    nanosleep (&t, &t2);
    printf("sleep end\n");
    return 0;
}

它完全按照我想要的方式工作。nanosleep 中的 Ctrl+c 立即中断它并通过打印“睡眠结束”继续执行。为什么 Windows 上的 SleepEx 不能进行类似的工作?

编辑第二个参数SleepEx当然应该是 TRUE。那是一个错字。

4

1 回答 1

1

无法回避这样一个事实,即您需要知道您正在中断什么,并且必须将代码设计为被中断。

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

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

如果您处于警报等待状态,您可以将 APC 排队到线程中。

如果您处于消息循环中,您可以发布消息或让循环使用MsgWaitForMultipleObjectsEx.

附加:演示代码演示如何唤醒SleepEx

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>

HANDLE mainthread;

VOID CALLBACK DummyAPCProc(
  _In_  ULONG_PTR dwParam
)
{
    printf("User APC\n");
    return;
}

void SleepIntr()
{
    printf("Entering sleep...\n");
    SleepEx(10000, TRUE);
    printf("Sleep done...\n");
}

static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) {
    printf("ctrl_handler pressed\n");
    // Wake program up!
    if (!QueueUserAPC(DummyAPCProc, mainthread, NULL))
    {
        printf("QueueUserAPC: %u\n", GetLastError());
        return TRUE;
    }
    return TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainthread, GENERIC_ALL, FALSE, 0))
    {
        printf("DuplicateHandle: %u\n", GetLastError());
        return 0;
    }

    SetConsoleCtrlHandler(ctrl_handler, TRUE);
    SleepIntr();
    printf("awake!\n"); 
    return 0;
}   
于 2014-03-18T21:01:28.020 回答