==================================================================== 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); } }