日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux进程signal,Linux Signal 示例

發布時間:2024/3/13 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux进程signal,Linux Signal 示例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

信號是系統響應某些條件而產生的一個事件,接收到該信的進程做出相應的處理。通常信是由錯誤產生的,如段錯誤(SIGSEGV)。 但信還可以作為進程間通信的一種方式,由一個進程發送給另一個進程。

信號定義在 signal.h 文件中,以 SIG 作為開頭,可用 kill -l 命令查看,詳細信息參見 man 7 signal。

信號處理

信號可以通過 signal 和 sigaction 函數來注冊處理, signal 函數是 struct sigaction 中 sa_handler 的一種便捷實現。

signal 函數

原型:

void (*signal(int sig, void (*func)(int)))(int);

其中 sig 是需要捕獲的 signal number, 后一個是捕獲到信號后的處理函數指針,所以處理函數的原型必須是 void func(int) ,簡單的代碼示例如下:

#include

#include

#include

static void

handler(int sig)

{

printf("Recieved signal: %d\n", sig);

}

int

main(int argc, char *argv[])

{

signal(SIGINT, handler);

printf("Caught SIGINT, input 'quit' to exit...\n");

// wait signal caught

char buf[1024] = {0};

while (1) {

printf("Please input: ");

scanf("%s", buf);

if (strcmp(buf, "quit") == 0) {

break;

}

}

printf("Exit...\n");

return 0;

}

另外 api 中也提供了下面 2 個特殊的 handler:

SIG_IGN

忽略此信號

SIG_DFL

恢復此信號的默認行為

sigaction 函數

原型:

int sigaction(int sig, const struct sigaction *restrict act,

struct sigaction *restrict oact);

其中 sig 為 signal number, act 指定信號的處理行為, oact 如果不為 NULL 則返回信號之前的處理行為。

struct sigaction 的主要成員如下:

類型

名稱

描述

void(*) (int)

sa_handler

處理函數指針,同 signal 函數中的 func 參數

sigset_t

sa_mask

信號屏蔽字,是指當前被阻塞的一組信號,不能被當前進程收到

int

sa_flags

處理行為修改器,指明哪種處理函數生效,詳見下文

void(*) (int, siginfo_t *, void *)

sa_sigaction

處理函數指針,僅 sa_flags == SA_SIGINFO 時有效

其中 sa_flags 主要可以設置為以下值:

SA_NOCLDSTOP

子進程停止時不產生 SIGCHLD 信號

SA_RESETHAND

將信號的處理函數在處理函數的入口重置為 SIG_DFL

SA_RESTART

重啟可中斷的函數而不是給出 EINTR 錯誤

SA_SIGINFO

使用 sa_sigaction 做為信號的處理函數

SA_NODEFER

捕獲到信號時不將它添加到信號屏蔽字中

簡單的代碼示例如下:

#include

#include

#include

#define SIG SIGINT

static void

sig_handler(int sig, siginfo_t *si, void *data)

{

printf("Caught signal: %d\n", sig);

printf("Sender pid: %d\n", si->si_pid);

printf("Sender uid: %d\n", si->si_uid);

}

static int

sig_caught(int sig)

{

printf("Start caught signal: %d\n", sig);

struct sigaction sa;

sa.sa_flags = SA_SIGINFO;

sa.sa_sigaction = sig_handler;

sigemptyset(&sa.sa_mask);

int ret = sigaction(sig, &sa, NULL);

if (ret == -1) {

printf("Failed to caught signal: %d\n", sig);

return -1;

}

return 0;

}

int

main(int argc, char *argv[])

{

if (sig_caught(SIG) == -1) {

return -1;

}

printf("Caught signal(%d), input 'quit' to exit...\n", SIG);

char buf[1024] = {0};

while(1) {

printf("Please input: ");

scanf("%s", buf);

if (strcmp(buf, "quit") == 0) {

break;

}

}

printf("Exit...\n");

return 0;

}

信號屏蔽字

考慮一下這種情況:在 signal()/sigaction() 返回之前進程就已經收到了需要處理的信號,此時進程會以默認行為來處理,這顯然不符合我們的期望。 這時就需要用到信號屏蔽字了,在進程啟動時就將需要處理的信號加入的屏蔽字中,等 signal()/sigaction() 返回后再解除屏蔽,解除屏蔽后至少會將收到的待處理信號發送一個給進程。

屏蔽字用到一下函數:

int sigemptyset(sigset_t *set);

int sigaddset(sigset_t *set, int signo);

int sigprocmask(int how, const sigset_t *restrict set,

sigset_t *restrict oset);

sigprocmask 中 set 為需要設置的屏蔽字集, oset 為之前的屏蔽字集, how 控制著 set 如何生效,可設置為以下值:

SIG_BLOCK

該進程的屏蔽字集將為當期屏蔽字集與 set 的并集, set 中包含了需要屏蔽的信號集

SIG_UNBLOCK

該進程的屏蔽字集將為當期屏蔽字集與 set 的補集的交集, set 中包含了需要解除屏蔽的信號集

SIG_SETMASK

該進程的屏蔽字集將設置為 set 的值

簡單的設置流程如下:

int

sig_block(int sig, int how)

{

sigset_t mask;

sigemptyset(&mask)

sigaddset(&mask, sig);

sigprocmask(how, &mask, NULL);

}

信號發送

信號可以通過 kill 函數發送給指定進程,也可以通過 raise 或者 alarm 函數發送給當前執行的線程或進程,下面來分別說說這幾個函數。

kill

原型:

int kill(pid_t pid, int sig);

kill 函數向指定進程發送指定的信號,如果信號為 0 將執行錯誤檢查,信號并不會發送,可以用來檢查 pid 的有效性。

pid 大于 0 時信號將發送給此進程, pid 小于等于 0 時,如下:

等于 0

信號將發送給發送者所在組里的所有進程

等于 -1

信號將發送給所有進程

小于 -1

信號將發送給進程組為 pid 絕對值的所有組內進程

alarm

原型:

unsigned alarm(unsigned seconds);

alarm 函數將在指定的 seconds 之后發送一個 SIGALRM 信號,如果 seconds 為 0, 則取消之前的定時器請求。如果不為 0 則取消之前的請求,重新設置為 seconds 。 如果在等待結束之前有其他的事件產生,那定時器請求也將被取消。

簡單的代碼示例如下:

#include

#include

#include

static void

handler(int sig)

{

printf("alarm arrived: %d\n", sig);

}

int

main(int argc, char *argv[])

{

signal(SIGALRM, handler);

alarm(2);

sleep(2);

printf("alarm 5s over\n");

alarm(10);

sleep(1);

unsigned int remaining = alarm(3);

printf("alarm 10s remain: %u, reset to 3\n", remaining);

sleep(3);

printf("alarm 3s over\n");

alarm(20);

sleep(3);

remaining = alarm(0);

printf("cancel alarm 20s, remian: %u, exit...\n", remaining);

}

raise

原型:

int raise(int sig);

raise 函數將給當前執行的線程或進程發送信號,如果信號處理函數已經被調用, raise 函數將等待信號處理函數調用結束才返回。

結語

信號處理函數是會被重復調用的,所以必要保存其是可重入的,注意處理邏輯。

另外本文中的代碼都在 signal 中,這個 repo 也有其它的示例,有興趣的可以看看。

附錄

信號表

/* ISO C99 signals. */

#define SIGINT 2 /* Interactive attention signal. */

#define SIGILL 4 /* Illegal instruction. */

#define SIGABRT 6 /* Abnormal termination. */

#define SIGFPE 8 /* Erroneous arithmetic operation. */

#define SIGSEGV 11 /* Invalid access to storage. */

#define SIGTERM 15 /* Termination request. */

/* Historical signals specified by POSIX. */

#define SIGHUP 1 /* Hangup. */

#define SIGQUIT 3 /* Quit. */

#define SIGTRAP 5 /* Trace/breakpoint trap. */

#define SIGKILL 9 /* Killed. */

#define SIGBUS 10 /* Bus error. */

#define SIGSYS 12 /* Bad system call. */

#define SIGPIPE 13 /* Broken pipe. */

#define SIGALRM 14 /* Alarm clock. */

/* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */

#define SIGURG 16 /* Urgent data is available at a socket. */

#define SIGSTOP 17 /* Stop, unblockable. */

#define SIGTSTP 18 /* Keyboard stop. */

#define SIGCONT 19 /* Continue. */

#define SIGCHLD 20 /* Child terminated or stopped. */

#define SIGTTIN 21 /* Background read from control terminal. */

#define SIGTTOU 22 /* Background write to control terminal. */

#define SIGPOLL 23 /* Pollable event occurred (System V). */

#define SIGXCPU 24 /* CPU time limit exceeded. */

#define SIGXFSZ 25 /* File size limit exceeded. */

#define SIGVTALRM 26 /* Virtual timer expired. */

#define SIGPROF 27 /* Profiling timer expired. */

#define SIGUSR1 30 /* User-defined signal 1. */

#define SIGUSR2 31 /* User-defined signal 2. */

/* Nonstandard signals found in all modern POSIX systems

(including both BSD and Linux). */

#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */

/* Archaic names for compatibility. */

#define SIGIO SIGPOLL /* I/O now possible (4.2 BSD). */

#define SIGIOT SIGABRT /* IOT instruction, abort() on a PDP-11. */

#define SIGCLD SIGCHLD /* Old System V name */

/* Not all systems support real-time signals. bits/signum.h indicates

that they are supported by overriding __SIGRTMAX to a value greater

than __SIGRTMIN. These constants give the kernel-level hard limits,

but some real-time signals may be used internally by glibc. Do not

use these constants in application code; use SIGRTMIN and SIGRTMAX

(defined in signal.h) instead. */

#define __SIGRTMIN 32

#define __SIGRTMAX __SIGRTMIN

/* Biggest signal number + 1 (including real-time signals). */

#define _NSIG (__SIGRTMAX + 1)

總結

以上是生活随笔為你收集整理的linux进程signal,Linux Signal 示例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。