簡體   English   中英

getline(3) 在收到信號 SIGINT (Ctrl+C) 后循環失敗

[英]getline(3) keeps failing on loop after receiving signal SIGINT (Ctrl+C)

getline()等待用戶輸入時,在接收到信號 SIGINT 時它會返回一個錯誤。 但是,在下一次調用getline()時,它會不斷返回錯誤,即使沒有發送其他信號。

這是該問題的最小化示例:

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

static void sig_handler(int signo) {
    fprintf(stderr, "SIGINT DETECTED\n");
}

int main(void) {
    struct sigaction sa;
    sigset_t smask;
    sigemptyset(&smask);
    sa.sa_handler = sig_handler;
    sa.sa_mask = smask;
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);

    while (1) {
        printf("Write something.\n");
        char *line = NULL;
        size_t buflen = 0;
        int res = getline(&line, &buflen, stdin);

        if (res == -1) {
            perror("getline()");
            free(line);
            continue;
        }

        printf("%s", line);
        free(line);
        break;
    }

    return 0;
}

我希望getline()在收到信號后會失敗(程序會打印錯誤),但是當循環重新啟動時,它會再次詢問“寫一些東西”。 並等待用戶輸入。

但是,在單個 SIGINT 信號之后, getline()將始終失敗(它不等待用戶輸入)並且程序將陷入無限循環:

Write something.
getline(): Interrupted system call
Write something.
getline(): Interrupted system call
Write something.
getline(): Interrupted system call
Write something.
getline(): Interrupted system call
...

如何“清除”由getline()中的 SIGINT 引起的錯誤,以使程序不會陷入無限循環?

您實際上用“清除錯誤”這句話回答了您自己的問題:您需要在重試getline之前調用clearerr(stdin)

(不相關的問題:在信號處理程序中調用像fprintf這樣的庫函數通常是不安全的,尤其是在這種情況下,處理程序可能在另一個庫 function 中運行時。除非特別說明,否則不保證標准庫函數是可重入的。)

由於要恢復讀取系統調用,因此需要設置SA_RESTART標志。

您目前正在清除它:

sa.sa_flags = 0;

相反,請執行以下操作:

sa.sa_flags = SA_RESTART;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM