信號量在在Linux中有著舉足輕重的地位滔金,Linux中一些異常錯誤也由信號量觸發(fā)拂封,另外信號量也可以用來做進(jìn)程間的通信,比如Nignx中master-worker模式的進(jìn)程通信就是使用信號量鹦蠕。
信號量的自定義處理
typedef void (*sig_t) (int)
sig_t signal(int sig, sig_t func)
sig
:自定義處理的信號量
func
:信號量的處理函數(shù)
信號量的屏蔽
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oldset)
how有三種模式
- SIG_BLOCK :屏蔽的信號量集合為
set
- SIG_UNBLOCK : 解出屏蔽的信號量集合為
set
- SIG_SETMASK : 設(shè)置的信號量集合為
set
特別注意信號量屏蔽階段,被屏蔽的信號量如果多次觸發(fā),在該信號量解出屏蔽時也只會再觸發(fā)一次。
信號量掛起
int sigsuspend(const sigset_t *sigmask)
該函數(shù)會阻塞當(dāng)前執(zhí)行的進(jìn)程,直到信號集中的信號觸發(fā)
特別注意,如果某個信號已經(jīng)被設(shè)置成BLOCK
模式的時候,再sisuspend
操作的信號集中如果有該信號,那么信號的BLOCK
模式將被取消,觸發(fā)就執(zhí)行相應(yīng)的處理在抛。
例子
下面用一個例子說明3個函數(shù)的使用方法
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
static int quit = 0;
static void Signal_handler(int s)
{
printf("Catch a signal:%d\n", s);
if( s == SIGQUIT)
{
printf("quit!\n");
quit = 1;
}
}
void Init_signal()
{
struct sigaction act;
act.sa_handler = Signal_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
sigaction(SIGUSR1, &act, NULL);
sigaction(SIGUSR2, &act, NULL);
sigaction(SIGBUS, &act, NULL);
}
void Block_signal()
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
if(sigprocmask(SIG_BLOCK, &set, NULL) < 0)
{
printf("sigprocmask error\n");
}
}
int main(int argc, char *argv[])
{
Init_signal();
Block_signal();
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
printf("%d\n", time(NULL));
while(1)
{
sigsuspend(&set);
printf("%d\n", time(NULL));
if( quit == 1)
{
break;
}
}
sigemptyset(&set);
sigsuspend(&set);
return 0;
}
假如進(jìn)程號為:1571
依次執(zhí)行以下操作:
kill -2 1571 //SIG_INT 信號
kill -3 1571 //SIG_QUIT 信號
執(zhí)行結(jié)果如下:
1479737350
Catch a signal:3
quit!
1479737379
Catch a signal:2
總結(jié)
信號量看似簡單,實(shí)則比較復(fù)雜,本文只介紹了單進(jìn)程單線程的信號量使用,多線程的使用比較復(fù)雜,還需要繼續(xù)學(xué)習(xí)钟病。