Skip to main content

Command Palette

Search for a command to run...

Sự kiện Ctrl+C trên Linux và Windows

Updated
3 min read

Trong hệ thống máy tính, khi có sự kiện xảy ra phần cứng có thể phát sinh một ngắt gửi đến CPU.

Ở tầng kernel, khi có interrupt xảy ra, CPU sẽ tạm dừng luồng đang chạy để chuyển sang xử lý sự kiện ngắt. Sau khi hoàn tất, CPU quay lại tiếp tục công việc trước đó.
Tuy nhiên, ở tầng ứng dụng (user-space), một số sự kiện như tổ hợp phím Ctrl+C được hệ điều hành chuyển thành các thông báo (signal hoặc event), và cách chuyển cũng như xử lý các thông báo này khác nhau giữa Linux và Windows.

Ctrl+C trên Linux

Trên Linux, khi người dùng nhấn Ctrl+C

  1. Kernel nhận ngắt từ bàn phím

  2. Kernel chuyển sự kiện này thành signal SIGINT

  3. Signal handler được thực thi trong chính context của thread nhận signal

Vì handler chạy trên luồng đang thực thi, nên trong thời gian xử lý signal, luồng chính bị tạm dừng.

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

// Hàm xử lý signal SIGINT (Ctrl+C) ở user-space
void signint_handle(int sig) {
    printf("Đã nhận tín hiệu Ctrl+C %d\n", sig);
    // Nghỉ 5 giây
    sleep(5);
    printf("Đang quay lại công việc ...\n");
}

int main() {
    // Đăng kí handler xử lý signal SIGINT
    signal(SIGINT, signint_handle);

    printf("Chương trình đang chạy, nhấn Ctrl+C để gửi signal SIGINT ...\n");

    while (1)
    {
        printf("Đang làm việc ...\n");
        // Nghỉ 1 giây
        sleep(1);
    }

    return 0;
}

Kết quả, luồng chính bị block cho đến khi hàm xử lý SIGINT hoàn thành.

Ctrl+C trên Windows

Trên Windows, Ctrl+C không được chuyển thành signal như Linux.
Thay vào đó, Console Subsystem của Windows:

  1. Bắt sự kiện CTRL_C_EVENT

  2. Tạo một luồng nội bộ riêng gọi hàm đã đăng ký bằng SetConsoleCtrlHandler()

Do handler chạy trên luồng riêng, chương trình chính vẫn tiếp tục chạy song song.

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

// Hàm xử lý sự kiện Console Ctrl+C (CTRL_C_EVENT) trên thread riêng
BOOL WINAPI ConsoleHandler(DWORD dwControlType) {
    switch (dwControlType) {
        // Tổ hợp phím Ctrl+C được nhấn
    case CTRL_C_EVENT:
        printf("Đã nhận tín hiệu Ctrl+C\n");
        // Tạm dừng 5 giây
        Sleep(5000);
        printf("Đang quay lại công việc ...\n");
        return TRUE;
    default:
        return FALSE;
    }
}

int main() {
    // Ép Console sử dụng bảng mã UTF-8 (Code Page 65001) để Hiển thị tiếng việt
    SetConsoleOutputCP(65001);

    // Đăng kí handler xử lý sự kiện Ctrl+C của Console (user-space)
    if(SetConsoleCtrlHandler(ConsoleHandler, TRUE)) {
        printf("Chương trình đang chạy, nhấn Ctrl+C để gửi CTRL_C_EVENT ...\n");
        while (1)
        {
            printf("Đang làm việc ...\n");
            // Nghỉ 1 giây
            Sleep(1000);
        }
    }

    return 0;
}

Kết quả, luồng xử lý sự kiện Ctrl+C chạy song song với luồng chính

The End.

Other

Part 1 of 1

More from this blog

U40 Học Code - Lập trình & Hệ điều hành

11 posts