信号関連機能

#include <sys/types.h>

#include <信号.h>

    int kill(pid_t pid, int sig);

    -機能: 任意のプロセス PID を与え、任意のシグナル署名を送信します。

    パラメータ:

        ピッド:

            >0: 指定されたプロセスにシグナルを送信します。

            =0: 現在のプロセス グループにシグナルを送信します。

            =-1: このシグナルを受信する許可を持つすべてのプロセスにシグナルを送信します。

            <-1: この pid = あるプロセス グループの ID の反転 (-12345)

        sig: 送信する必要があるシグナルの番号またはマクロ値。0 はシグナルを送信しないことを意味します

    int raise(int sig);

    -機能: 現在のプロセスにシグナルを送信します。

    -パラメータ:

        -sig: 送信する信号

    -戻り値:

        -成功0

        - ゼロ以外の失敗

    ボイド中止(ボイド);

        機能: SIGABRT シグナルを現在のプロセスに送信し、現在のプロセスを強制終了します。

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include <unistd.h>
int main() {
    pid_t pid = fork();
    if(pid == 0) {
        //子进程
        int i = 0;
        for(i = 0; i < 5; i++) {
            printf("child process\n");
            sleep(1);
        }
    } else if(pid > 0) {
        //父进程
        printf("parent process\n");
        sleep(2);
        printf("kill child process now\n");
        kill(pid, SIGINT);
    }
    return 0;
}

アラーム機能

#include <unistd.h>

unsigned int アラーム (unsigned int 秒);

    -機能: タイマーを設定します。関数呼び出しによりカウントダウンが開始されます。カウントダウンが 0 に達すると、関数は現在のプロセスにシグナルを送信します: SIGALARM

    -パラメータ:

        秒: カウントダウン期間、単位: 秒。パラメータが 0 の場合、タイマーは無効です (カウントダウンなし、信号は送信されません)。

            アラーム(0)を介してタイマーをキャンセルします。

    ・戻り値:カウントダウンの残り時間

        - 前にタイマーがない場合、0 を返します

        - 以前にタイマーがあった場合、前のタイマーの残り時間を返します

    -SIGALARM: デフォルトで現在のプロセスを終了します。各プロセスにはタイマーが 1 つだけあります。

    アラーム(10); ->0を返す

    1秒経過

    アラーム(5); ->リターン9

    この関数はノンブロッキングです

#include<stdio.h>
#include<unistd.h>
int main() {
    int ret = alarm(5);
    printf("ret = %d\n", ret);
    sleep(2);
    ret = alarm(10);
    printf("ret = %d\n", ret);
    while(1) {
    }
    return 0;
}

セットタイマー

#include <sys/time.h>

    int setitimer(int that, const struct itimerval *new_value,struct itimerval *old_value);

    機能:タイマー(目覚まし時計)を設定します。アラーム機能を置き換えることができます。精度が高く、定期的なタイミングを実現できます

    -パラメータ:

        -どれ: タイマーは何時間をカウントしますか?

            -ITIMER_REAL: リアルタイム、到着時刻、一般的に使用される送信 SIGALRM

            -ITIMER_VIRTUAL: ユーザー時間、到着時間、SIGVTALRM の送信

            -ITIMER_PROF: ユーザーモードとカーネルモードでプロセスが費やした時間に基づいて到着時間を計算し、SIGPROF を送信します。

        -new_value: タイマーのプロパティを設定します。

            struct itimerval { //タイマーの構造体

               struct timeval it_interval; //インターバル時間

               struct timeval it_value; //タイマーの実行をどれだけ遅らせるか

           };

           struct timeval { //時間の構造

               time_t      tv_sec;   //秒数    

               suseconds_t tv_usec; //マイクロ秒

           };

        -old_value: 最後のタイミングの時間パラメータを記録します。

    戻り値: 成功した場合は 0、失敗した場合は -1、エラー番号を設定

#include<stdio.h>
#include <sys/time.h>
#include <stdlib.h>
//过3秒后,每隔2秒定时一次
int main() {
    struct itimerval new_value;
    //设置值
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;
    //设置延迟的时间
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;
    int ret = setitimer(ITIMER_REAL, &new_value, NULL);
    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }
    getchar();
    return 0;
}

信号機能

    #include <signal.h>
    typedef void (*sighandler_t)(int);
    sighandler_t signal(intsignum, sighandler_t handler);
        - 機能: 特定のシグナルのキャプチャ動作を設定します
        - パラメータ:
            -signum: キャプチャするシグナル
            -ハンドラー: シグナルをキャッチした後にシグナルを処理する方法
                - SIG_IGN: シグナルを無視する
                - SIG_DFL: シグナルのデフォルトの動作を使用する
                - コールバック関数: この関数はカーネル呼び出しであり、プログラマはシグナルの処理方法を記述することのみを担当します信号をキャッチした後。
                コールバック関数:
                    - プログラマが実装し、事前に準備する必要があります。関数のタイプは実際のニーズに基づいています。関数ポインタの定義を参照してください。 - プログラマによって呼び出されるのではなく、カーネルによって呼び出されます
                    。シグナル発生時
                    - 関数ポインタはコールバックを実装する手段であり、関数実装後は関数ポインタの位置に関数名を置くだけです。

        - 戻り値:
            成功、最後に登録された信号処理関数のアドレスを返します。最初の呼び出しは
            NULL を返すことができず、SIG_ERR を返します。設定されたエラー番号
            
    SIGKILL SIGSTOP はキャプチャまたは無視できません。

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void myalarm(int num) {
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}

// 过3秒以后,每隔2秒钟定时一次
int main() {

    // 注册信号捕捉
    // signal(SIGALRM, SIG_IGN);
    // signal(SIGALRM, SIG_DFL);
    // void (*sighandler_t)(int); 函数指针,int类型的参数表示捕捉到的信号的值。
    signal(SIGALRM, myalarm);

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    getchar();

    return 0;
}

シグアクション関数

1. ユーザーがキーボードの Ctrl + C を押してシグナル No. 2 SIGINT を生成します (シグナルが作成されます)。

2. 信号は生成されるが処理されない (保留)
    - すべての未処理の信号はカーネル内のセット (保留信号セット) に格納されます
    - SIGINT 信号のステータスは 2 番目のフラグ ビットに格納されます
        - このフラグ ビットの値は 0、信号が保留状態にないことを示します
        。このフラグ ビットの値は 1 で、信号が保留状態にあることを示します。
    
3. この保留状態の信号は処理する必要があり、別の信号と結合する必要があります。信号セット (ブロック信号セット)、比較
    - ブロック信号セットはデフォルトでは信号をブロックしません
    - 特定の信号をブロックしたい場合、ユーザーはシステム API を呼び出す必要があります

4. 処理中に、ブロックされた信号セット内のフラグ ビットをクエリして、信号がブロックされているかどうかを確認します。ブロックされてい
    ない場合、信号は処理されます
    。ブロックされている場合、信号は、ブロックが解放されるまで保留され続けます。信号が処理される

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

int main() {

    // 创建一个信号集
    sigset_t set;

    // 清空信号集的内容
    sigemptyset(&set);

    // 判断 SIGINT 是否在信号集 set 里
    int ret = sigismember(&set, SIGINT);
    if(ret == 0) {
        printf("SIGINT 不阻塞\n");
    } else if(ret == 1) {
        printf("SIGINT 阻塞\n");
    }

    // 添加几个信号到信号集中
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGQUIT);

    // 判断SIGINT是否在信号集中
    ret = sigismember(&set, SIGINT);
    if(ret == 0) {
        printf("SIGINT 不阻塞\n");
    } else if(ret == 1) {
        printf("SIGINT 阻塞\n");
    }

    // 判断SIGQUIT是否在信号集中
    ret = sigismember(&set, SIGQUIT);
    if(ret == 0) {
        printf("SIGQUIT 不阻塞\n");
    } else if(ret == 1) {
        printf("SIGQUIT 阻塞\n");
    }

    // 从信号集中删除一个信号
    sigdelset(&set, SIGQUIT);

    // 判断SIGQUIT是否在信号集中
    ret = sigismember(&set, SIGQUIT);
    if(ret == 0) {
        printf("SIGQUIT 不阻塞\n");
    } else if(ret == 1) {
        printf("SIGQUIT 阻塞\n");
    }

    return 0;
}

シグプロマスク

   int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
       - 機能: カスタム信号セットのデータをカーネルに設定します (ブロック、ブロック解除、置換を設定)
       - パラメーター:
           - how: 信号をブロックする方法カーネル処理用のセット
               SIG_BLOCK: ユーザーが設定したブロッキング信号セットをカーネルに追加します。カーネル内の元のデータは変更されません。カーネル内のデフォルトのブロッキング信号セットはマスクであると仮定します。マスク | set
                   SIG_UNBLOCK
               :ユーザーによって設定されたデータ、カーネルで設定されたブロッキング信号セットを処理します。データは
                   マスクのブロックを解除するために使用されます &= ~set
               SIG_SETMASK: カーネル内の元の値を上書きします
           
           - set: 初期化されたユーザー定義の信号セット
           - oldset : 設定前にカーネルに設定されたブロッキング信号のステータスを保存します。これは NULL にすることができます
       - 戻り値:
           成功: 0
           失敗: -1
               設定エラー番号: EFAULT、EINVAL

   int sigpending(sigset_t *set);
       - 機能: カーネルに設定されている保留信号を取得します
       - パラメータ: set、発信パラメータ、カーネルに設定されている保留信号の情報を保存します。

// 编写一个程序,把所有的常规信号(1-31)的未决状态打印到屏幕
// 设置某些信号是阻塞的,通过键盘产生这些信号

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

int main() {

    // 设置2、3号信号阻塞
    sigset_t set;
    sigemptyset(&set);
    // 将2号和3号信号添加到信号集中
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGQUIT);

    // 修改内核中的阻塞信号集
    sigprocmask(SIG_BLOCK, &set, NULL);

    int num = 0;

    while(1) {
        num++;
        // 获取当前的未决信号集的数据
        sigset_t pendingset;
        sigemptyset(&pendingset);
        sigpending(&pendingset);

        // 遍历前32位
        for(int i = 1; i <= 31; i++) {
            if(sigismember(&pendingset, i) == 1) {
                printf("1");
            }else if(sigismember(&pendingset, i) == 0) {
                printf("0");
            }else {
                perror("sigismember");
                exit(0);
            }
        }

        printf("\n");
        sleep(1);
        if(num == 10) {
            // 解除阻塞
            sigprocmask(SIG_UNBLOCK, &set, NULL);
        }

    }


    return 0;
}

おすすめ

転載: blog.csdn.net/ME_Liao_2022/article/details/133250854