Linux 信号可靠性,同步,异步,多线程信号等介绍
鑒于網上超多關于Linux信號處理相關的文章,本篇關于基本的信號知識不再普及,只提出一些平時不常關注或者關注不到的一些方面:
1. 信號可靠性:此可靠指的是信號是否會排隊,并不是指信號會丟失(其實在也可以理解為不排隊的信號就會丟失)。SIGRTMIN以下的信號不會被排隊處理,即只傳遞一次,如果進程已經有信號還未被處理,后面再來同樣的信號即丟失,其他的不同信號還是進入排隊處理。SIGRTMIN以上的信號,都會進入隊列
2. 信號異步處理:進程注冊的信號處理函數將在進程內核態返回用戶態時被調用,相對于進程主線程或其他線程來說,是并行處理的
3. 信號同步處理:進程可以選擇以同步的方式來處理信號,比如由一個特定的線程來處理
4. 多線程中的信號:對于內核來說,沒有進程與線程的區分,所有都是進程;對于進程來說,所有線程共享進程地址空間,包括注冊的信號,即子線程會繼承主線程所注冊的信號環境
5. 誰來執行信號處理函數:異步處理時由最小號的線程來處理;同步處理時由用戶特定的調用同步函數的線程來執行
6. 誰可以注冊信號:誰都可以注冊,主線程子線程都可以;注冊與處理不是相關聯的
7. 在多個地方注冊信號了處理函數,將怎么處理:信號處理函數將以最后調用的信號注冊函數為準
關于信號API:
異步處理 sigaction:
void sig_handler(int signum) {... }struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = sig_handler; sigemptyset(&action.sa_mask); action.sa_flags = 0; /* restart property */ action.sa_flags |= SA_RESTART; sigaction(SIGUSR2, &action, NULL);同步處理 sigwaitinfo:
void* sub_sig_handle_thread() {sigset_t waitset, oset;siginfo_t info;int rc;pthread_t ppid = pthread_self();pthread_detach(ppid);sigemptyset(&waitset);sigaddset(&waitset, SIGRTMIN);sigaddset(&waitset, SIGUSR1);while (1) {rc = sigwaitinfo(&waitset, &info);if (rc != -1) {printf("<--sigwaitinfo() fetch the signal %d\n", rc);sig_handler(info.si_signo);} else {printf("<--sigwaitinfo() return err: %d; %s\n", errno, strerror(errno));}} }在某個獨立的線程中,循環調用sigwaitinfo檢測是否有未處理的信號,有則主動調用信號處理函數
多線程信號繼承:
1. 每個線程都有自己獨立的signal mask,但所有線程共享進程的signal action
2. 主線程調用pthread_sigmask創建信號屏蔽策略,將被所有子線程繼承
3. pthread_kill 發送的目的線程需要與調用線程再同一個進程之中
4. 跨進程發送信號使用kill 指定進程PID
5. 同步處理時,子線程sigaddset的信號必須是主線程sigaddset的子集
同步、異步處理共存:
1. 同樣的信號同時都被同步異步所注冊,同步優先級更高,將以同步方式處理
2. 不同信號可以被不同方式處理,比如同步處理SIGUSR1的同時可以異步處理SIGUSR2
測試例程:
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <pthread.h> #include <unistd.h> #include <sys/types.h>#define MUTIL_THREAD 1void sig_handler(int signum) {static int j = 0;static int k = 0;pthread_t sig_ppid = pthread_self(); // used to show which thread the signal is handled in.printf("<-- get sig %d\n", signum);if (signum == SIGUSR1) {printf("<--thread %ld, receive SIGUSR1 No. %d\n", sig_ppid, j);j++;//SIGRTMIN should not be considered constants from userland, //there is compile error when use switch case} else if (signum == SIGRTMIN) {printf("<--thread %ld, receive SIGRTMIN No. %d\n", sig_ppid, k);k++;} else if (signum == SIGUSR2) {printf("<--thread %ld, receive SIGUSR2\n", sig_ppid);} }void* worker_thread() {pthread_t ppid = pthread_self();pthread_detach(ppid);int ret = 0;struct timeval tv = {10, 0}; //10swhile (1) {printf("I'm thread %ld, I'm alive\n", ppid);tv.tv_sec = 10;ret = select(0, NULL, NULL, NULL, &tv);if(ret < 0)printf("thread %ld interrupt by signal\n", ppid);//sleep(10);} }void* sigmgr_thread() {sigset_t waitset, oset;siginfo_t info;int rc;pthread_t ppid = pthread_self();pthread_detach(ppid);#if MUTIL_THREADsigemptyset(&waitset);sigaddset(&waitset, SIGRTMIN);sigaddset(&waitset, SIGUSR1); #elsestruct sigaction action;memset(&action, 0, sizeof(action)); action.sa_handler = sig_handler;sigemptyset(&action.sa_mask);action.sa_flags = 0;/* restart property */action.sa_flags |= SA_RESTART;sigaction(SIGUSR2, &action, NULL); #endifwhile (1) {rc = sigwaitinfo(&waitset, &info);if (rc != -1) {printf("<--sigwaitinfo() fetch the signal %d\n", rc);sig_handler(info.si_signo);} else {printf("<--sigwaitinfo() return err: %d; %s\n", errno, strerror(errno));}} }int main() {sigset_t bset, oset;int i;pid_t pid = getpid();pthread_t ppid[7];struct sigaction action;memset(&action, 0, sizeof(action)); action.sa_handler = sig_handler;sigemptyset(&action.sa_mask);action.sa_flags = 0;/* restart property */action.sa_flags |= SA_RESTART;#if MUTIL_THREADsigaddset(&action.sa_mask, SIGRTMIN);sigaddset(&action.sa_mask, SIGUSR1); //handle by sub-thread // sigaddset(&action.sa_mask, SIGUSR2);if(pthread_sigmask(SIG_BLOCK, &action.sa_mask, &oset) != 0)printf("!! Set pthread mask failed\n");sigaction(SIGUSR2, &action, NULL); //handle by main #elsesigaction(SIGUSR1, &action, NULL);sigaction(SIGRTMIN, &action, NULL); //only main #endifprintf("main pid %d, %ld\n", pid, pthread_self());// Create the dedicated thread sigmgr_thread() which will handle // SIGUSR1 and SIGRTMIN synchronouslypthread_create(&ppid[0], NULL, sigmgr_thread, NULL);// Create 5 worker threads, which will inherit the thread mask of// the creator main threadfor (i = 0; i < 5; i++) {pthread_create(&ppid[i+1], NULL, worker_thread, NULL);}//wait sub-thread to regist signalsleep(3);// send out 50 SIGUSR1 and SIGRTMIN signalsfor (i = 0; i < 5; i++) {printf("\n-->main thread, send SIGUSR1 No. %d\n", i);kill(pid, SIGUSR1);printf("-->main thread, send SIGRTMIN No. %d\n", i);kill(pid, SIGRTMIN);printf("-->main thread, send SIGUSR2 No. %d\n", i);kill(pid, SIGUSR2);sleep(1);}struct timeval tv = {50, 0};int ret = select(0, NULL, NULL, NULL, &tv);if(ret < 0)printf("main interrupt by signal\n");return 0; }運行結果:
main pid 12018, 140114995099392
I'm thread 140114978449152, I'm alive
I'm thread 140114970056448, I'm alive
I'm thread 140114953271040, I'm alive
I'm thread 140114944878336, I'm alive
I'm thread 140114961663744, I'm alive
-->main thread, send SIGUSR1 No. 0
-->main thread, send SIGRTMIN No. 0
-->main thread, send SIGUSR2 No. 0
<-- get sig 12
<--thread 140114995099392, receive SIGUSR2??? --->主線程處理USR2
<--sigwaitinfo() fetch the signal 10
<-- get sig 10
<--thread 140114986841856, receive SIGUSR1 No. 0?? -->同步處理信號
<--sigwaitinfo() fetch the signal 34
<-- get sig 34
<--thread 140114986841856, receive SIGRTMIN No. 0?? -->同步處理信號
-->main thread, send SIGUSR1 No. 1
-->main thread, send SIGRTMIN No. 1
-->main thread, send SIGUSR2 No. 1
<--sigwaitinfo() fetch the signal 10
<-- get sig 10
<--thread 140114986841856, receive SIGUSR1 No. 1
<--sigwaitinfo() fetch the signal 34
<-- get sig 34
<--thread 140114986841856, receive SIGRTMIN No. 1
<-- get sig 12
<--thread 140114995099392, receive SIGUSR2
總結
以上是生活随笔為你收集整理的Linux 信号可靠性,同步,异步,多线程信号等介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux CMA使用机制分析--基于S
- 下一篇: 记最近Linux中遇到cpu使用率低lo