Linux-signal異步通知機制

Linux中的信號

kill -9 pid #kill只是起到發送信號的作用,-9參數纔是殺死進程
ctrl+c相當於kill 2 pid
3和9不可被捕捉替換
信號可做兩個進程之間的通訊,同步,而不是發送數據

#define SIGHUP		 1
#define SIGINT		 2
#define SIGQUIT		 3
#define SIGILL		 4
#define SIGTRAP		 5
#define SIGABRT		 6
#define SIGIOT		 6
#define SIGBUS		 7
#define SIGFPE		 8
#define SIGKILL		 9
#define SIGUSR1		10
#define SIGSEGV		11
#define SIGUSR2		12
#define SIGPIPE		13
#define SIGALRM		14
#define SIGTERM		15
#define SIGSTKFLT	16
#define SIGCHLD		17
#define SIGCONT		18
#define SIGSTOP		19
#define SIGTSTP		20
#define SIGTTIN		21
#define SIGTTOU		22
#define SIGURG		23
#define SIGXCPU		24
#define SIGXFSZ		25
#define SIGVTALRM	26
#define SIGPROF		27
#define SIGWINCH	28
#define SIGIO		29
#define SIGPOLL		SIGIO
/*
#define SIGLOST		29
*/
#define SIGPWR		30
#define SIGSYS		31
/* signal 31 is no longer "unused", but the SIGUNUSED macro remains for backwards compatibility */
#define	SIGUNUSED	31

/* These should not be considered constants from userland.  */
#define SIGRTMIN	32
#define SIGRTMAX	_NSIG
//捕獲signum信號,重新定義這個信號的操作函數爲myfunc()
signal(int signum,myfunc());
signal(SIGINT,myfunc);
signal(SIGINT,SIG_IGN);//參數SIG_IGN表示忽略這個信號,但quite和kill信號無法屏蔽

如何發起異步操作
kill 命令 eg:kill -signum pid
int kill(pid,signum);
pid>0 發給pid進程
pid=0 發給當前進程組的所有進程(fork出來的進程)
pid=-1 發送給所有進程
pid<0 發送給|PID|所對應的組上

pid=getpid()
gpid=getgpid()    

raise
自舉信號,會給自己發送一個信號

   int raise(int sig);
   int kill(getpid(),signum);

alarm
定時函數

unsigned int alarm(unsigned int seconds);

函數會在所指定的seconds之後收到SIGALRM信號

signal(SIGALRM,printf);
alarm(2);

第二次設置alarm時,會立即返回上次未消耗地時間
在這裏插入圖片描述
ualarm

  useconds_t ualarm(useconds_t usecs, useconds_t interval);

以useconds爲單位,第一個參數爲第一次產生時間,第二個參數爲間隔產生
setitimer 定時器

int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
                     struct itimerval *old_value);

Linux會給進程提供三個定時器
ITIMER_REAL:以逝去時間遞減
ITIMER_VIRTUAL:

 struct itimerval {
               struct timeval it_interval; /* next value */
               struct timeval it_value;    /* current value */
           };

           struct timeval {
               time_t      tv_sec;         /* seconds */
               suseconds_t tv_usec;        /* microseconds */
           };

信號可能會打斷阻塞函數,可以用來做超時響應
在這裏插入圖片描述
因爲信號可能打斷accept阻塞,所以還要判斷一次錯誤類型,如果是打斷,則重新accept
獲取文件大小方法
在這裏插入圖片描述
sigaction對象
在早期,signal(int signum,myfunc());沒有設計得比較周全,只能給綁定的函數傳入一個信號類型的參數,所以後期纔有了sigaction對象

int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);

struct sigaction 
{		//兩個函數指針只調用其一,通過sa_flags設置
       void     (*sa_handler)(int);//若調用此,和普通signal函數沒區別
       //信號類型,發射信號時當前進程系統信息結構體(如下),給sa_handler傳的參數,通過sigqueue方法發送
       void     (*sa_sigaction)(int, siginfo_t *, void *);
       sigset_t   sa_mask;//信號屏蔽集
       int        sa_flags;  //會影響信號接受特殊標誌,可設置爲0(只調用sa_handler)和SA_SIGINFO(調用sa_sigaction)
       void     (*sa_restorer)(void);

};
siginfo_t {
   int      si_signo;    /* Signal number */
   int      si_errno;    /* An errno value */
   int      si_code;     /* Signal code */
   int      si_trapno;   /* Trap number that caused
                            hardware-generated signal
                            (unused on most architectures) */
   pid_t    si_pid;      /* Sending process ID */
   uid_t    si_uid;      /* Real user ID of sending process */
   int      si_status;   /* Exit value or signal */
   clock_t  si_utime;    /* User time consumed */
   clock_t  si_stime;    /* System time consumed */
   sigval_t si_value;    /* Signal value */
   int      si_int;      /* POSIX.1b signal */
   void    *si_ptr;      /* POSIX.1b signal */
   int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
   int      si_timerid;  /* Timer ID; POSIX.1b timers */
   void    *si_addr;     /* Memory location which caused fault */
   long     si_band;     /* Band event (was int in
                            glibc 2.3.2 and earlier) */
   int      si_fd;       /* File descriptor */
   short    si_addr_lsb; /* Least significant bit of address
                            (since Linux 2.6.32) */
}
  • 信號會喚醒當前進程的阻塞狀態
    sigqueue
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<string.h>

int main(int argc,char *argv[])
{
    if(argc!=2)
    {
        printf("arguments error!");
        exit(0);
    }

    pid_t pid=atoi(argv[1]);//將進程號轉化爲整數
    union sigval v;
    v.sival_int=100;
    //這兒只是利用SIGINT來發送數據,
    //任何信號都行,只需要發送端與接收端規定一致即可
    sigqueue(pid,SIGINT,v);//給一pid發送信號和void *參數
    return 0;
}

sigval_t

union sigval {
    int sival_int;
    void *sival_ptr;
};

信號集合
信號集是爲了方便批量設置屏蔽(不接收)各種信號,SIG_IGN是忽略(接收不處理)
用位圖的形式(如一個int有32位)存儲信號

  • sigset_t sa_mas

int sigemptyset(sigset_t *set);//清空
int sigfillset(sigset_t *set);//填充
int sigaddset(sigset_t *set, int signum);//給信號集添加信號
int sigdelset(sigset_t *set, int signum);//刪除
int sigismember(const sigset_t *set, int signum);//查找

設置信號屏蔽集合
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);//第三個參數用來做上一集合備份
第一個參數爲一下幾種
SIG_BLOCK//阻塞
SIG_UNBLOCK//非阻塞
SIG_SETMASK//屏蔽

未決信號
sigpending(sigset)用來獲取已接收的被屏蔽信號,若此信號解除屏蔽,會立即執行一次此信號的回調函數

int block
32bit
00000000000000000000000000000100

sigsuspend 函數 等待信號
阻塞接收所設置的信號,若接收了其他信號,則解除阻塞往下運行
int sigsuspend(const sigset_t *mask);
運用signal IO做socket觸發
要用fcntl給skcket綁定個PID,因爲signal需要通過PID發送
設置dev時儘量不要用 fcntl設置,用ioctl在這裏插入圖片描述
參考
https://blog.csdn.net/freeking101/article/details/78338497

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章