IPC研究(1) -- signals

==================================================================== IPC ---- Signals Question: Why is it unsafe to call printf() in a signal handler? A: A signal handling fucntion could be interrupted in the middle and called again by something eles. So a signal handling function is not just recurisve, but also re-entrant. This means, any system calls that are not re-entrant but are called inside a signal handler are considered unsafe. For system calls that are safe to call inside a signal handler, refer to page 524 in Book "Linux Programming". Related system calls: signal (deprecated) kill pause sigaction (recommended) sigemptyset sigdelset sigfillset sigismember sigpending sigsuspend Note: When programming with signals, we should manipulater the signal set carefully. Sigaction offers additional operations on sigset, eg. masking out a signal. That's why sigaction is more robust then signal. struct sigaction {                void     (*sa_handler)(int);                void     (*sa_sigaction)(int, siginfo_t *, void *);                sigset_t   sa_mask;                int        sa_flags;                void     (*sa_restorer)(void);            }; The field sa_mask could be used to set the signal mask. The field sa_flags is used to modify the signal behavior. For example, many system calls are interruptalbe, if some interruptable system call receives a signal, it sets errno to EINTR and returns. If sa_flag is specified as SA_RESART, the interrruptable function will be restarted instead of being interrupted. Analysis: 1. signal IPC機制是一種很基本的相對比較弱的IPC機制。它的「弱「主要表如今如下幾個方面。     第一,若是進程A和B要進行通訊,他們之間能夠傳遞的信息,其實就是個數字signum。因此,信息量是不多的。     第二,signum有限,而且預約義了一些行爲。若是你改變這些預約義的行爲,會使得程序難以理解。這一點,咱們能夠經過NPTL的設計文檔來了解更多。用LWP來實現線程,致使其間用signal通訊很不方便,使得整個signal系統破破碎碎的,因此後來纔有了NPTL支持。     第三,A和B之間用signal進行通信,會使得這兩個進程耦合成都很是高。首先,A和B之間要現對每一個SIGxxx有共同的行爲定義;其次,若是A要發送signal給B,它必需要知道B的PID,若是AB不是父子進程的話,這一點有點麻煩。標準c庫中,沒有相似get_pid_by_name()這種函數。因此,你必需要本身實現這個函數。簡單的方法是經過系統的/proc目錄進行操做。     第四,不管是得到pid仍是自己signal通信的維護,都須要額外的開銷,給編程帶來不利。     Example: #include <unistd.h> #include <signal.h> #include <stdio.h> void handler_usr1(int sig) {         printf("[%s] is running ... \n", __func__); /* unsafe, should not be called in a practical program */         sleep(10);         printf("[%s] exited \n", __func__); } void main() {         struct sigaction act;         act.sa_handler = handler_usr1;         sigfillset(&act.sa_mask); /* mask out all signals */         act.sa_flags = 0;         sigaction(SIGUSR1, &act, 0);         while (1)         {                 printf("[%s] is running ... \n", __func__);                 sleep(2);         } } 要經過進程名字來得到pid,能夠經過/proc。以下: /proc/23697 $ cat status Name:    sigaction_test State:    S (sleeping) Tgid:    23697 Pid:    23697 PPid:    2309 TracerPid:    0 Uid:    1000    1000    1000    1000 Gid:    1000    1000    1000    1000 FDSize:    256 Groups:    4 20 24 46 105 119 122 1000 經過字符串,操做,能夠得到PID。 #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> #include <signal.h> #define MAX_INFO_LEN 4096 /**  * function: get_pid_by_name  * @return: -1 if failed, pid of process[name] if succeeded  **/ pid_t get_pid_by_name(const char* name) {     DIR *dir;     struct dirent *ent;     char *endptr;     char buf[MAX_INFO_LEN];     if ( !(dir=opendir("/proc")) )     {         perror("can not open /proc");         exit(-1);     }     while( (ent = readdir(dir) ) != NULL)     {         long lpid = strtol(ent->d_name, &endptr, 10);         if (*endptr != '\0') /* not a proc dir indicating a running process */         {             continue;         }         memset(buf, 0, sizeof(buf));         snprintf(buf, sizeof(buf), "/proc/%ld/status", lpid);         FILE *fp = fopen(buf, "r");         if (fp)        /* not null */         {             if ( fgets(buf, sizeof(buf), fp) != NULL )             {                 /* check the second token in the file, i.e. the program name */                 char *first = strtok(buf, "\t");                 char *second = strtok(NULL, "\n");                 printf("[%s]\n", second);                 if (!strcmp(second, name))                 {                     fclose(fp);                     closedir(dir);                     return (pid_t)lpid;                 }             }             fclose(fp);         }//examine "/proc/[lpid]/status"         else         {             printf("open [%s] faild \n", buf);         }     }//while     /* no corresponding process in /proc */     return -1; } void main() {     char *name = "processB";     pid_t pid = get_pid_by_name(name);     if (pid == -1)     {         printf("no process found with name [%s] \n", name);         exit(-1);     }     else     {         printf("sending [%s] SIGUSR1 \n", name);         kill(pid, SIGUSR1);     } }
相關文章
相關標籤/搜索