信号是linux所使用的进程间通信的最古老的方式。它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式 。一个完整的信号周期包括三个部分,信号的产生,信号在进程中的注册,信号在进程中的注销,执行信号处理函数。如下图所示:

注意:这里信号的产生,注册,注销时信号的内部机制,而不是信号的函数实现。
对信号的响应由三种方式:
1、忽略信号,即对信号不做任何的处理。处SIGKILL和SIGSTOP除外。
2、捕捉该信号,定义信号处理函数,当信号发生时,执行信号处理函数。
3、执行缺省操作,linux对每种信号都有默认的操作。
信号的发送通过kill函数和raise函数,两者的区别在于raise函数可以向本进程发送信号。


下面的代码展示了如何使用两个函数:
在实例中首先fork了一个子进程,为了保证子进程不在父进程调用kill函数之前退出,使用raise函数向子进程发送SINSTOP函数,将子进程暂停。接下来再在父进程中执行kill函数。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int ret;
if((pid=fork())<0){
perror("fork");
exit(1);
}
if(pid == 0){
raise(SIGSTOP);
exit(0);
}
else{
printf("pid=%d\n",pid);
if((waitpid(pid,NULL,WNOHANG))==0){
if((ret=kill(pid,SIGKILL))==0)
printf("kill %d\n",pid);
else{
perror("kill");
}
}
}
}
程序执行的结果:

信号处理的方法有两种,一种是使用signal函数进行处理,另一种使用信号集函数。
signal函数:
使用signal函数时只需将处理的信号和处理的函数列出即可。

下面使用代码展示如何使用signal函数:
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
static void sig_usr(int signo);
int main(void)
{
if(signal(SIGUSR1,sig_usr) == SIG_ERR)
printf("Can't catch SIGUSR1");
if(signal(SIGUSR2,sig_usr) == SIG_ERR)
printf("Can't catch SIGUSR2");
for(;;)
pause();
}
static void sig_usr(int signo)
{
if(signo == SIGUSR1)
printf("recevied SIGUSR1\n");
else if (signo == SIGUSR2)
printf("received SIGUSR2\n");
else
printf("received signal %d\n",signo);
}
执行程序在后台运行:./signal &

第二种是信号集处理信号:
信号集是一个能表示多个信号的数据类型,sigset_t set ;set即一个信号集。
既然是一个集合,就需要对集合进行添加/删除等操作。
int sigemptyset(sigset_t *set); 将set集合置空
int sigfillset(sigset_t *set); 将所有信号加入set集合
int sigaddset(sigset_t *set,int signo); 将signo信号加入到set集合
int sigdelset(sigset_t *set,int signo); 从set集合中移除signo信号
int sigismember(const sigset_t *set,int signo); signo判断信号是否存在于set集合中
信号处理的过程如下:



struct sigaction {
void (*sa_handler)();/*处理函数或SIG_IGN(忽略)或SIG_DFL(默认)*/
sigset_t sa_mask; /*处理函数过程中被阻塞*/
int sa_flags; /*标志位,对信号进程处理选项*/
} ;
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
//自定义信号处理函数
void my_func(int signum)
{
printf("If you want to quit,please try SIGQUIT\n");
}
int main()
{
sigset_t set,pendset;
struct sigaction action1,action2;
//初始化信号集为空
if(sigemptyset(&set)<0)
perror("sigemptyset");
//将相应的信号加入信号集
if(sigaddset(&set,SIGQUIT)<0)
perror("sigaddset");
if(sigaddset(&set,SIGINT)<0)
perror("sigaddset");
//设置信号集屏蔽字
if(sigprocmask(SIG_BLOCK,&set,NULL)<0)
perror("sigprocmask");
else
{
printf("blocked\n");
sleep(5);
}
if(sigprocmask(SIG_UNBLOCK,&set,NULL)<0)
perror("sigprocmask");
else
printf("unblock\n");
//对相应的信号进行屏蔽处理
while(1){
if(sigismember(&set,SIGINT)){
sigemptyset(&action1.sa_mask);
action1.sa_handler=my_func;
sigaction(SIGINT,&action1,NULL);
}else if(sigismember(&set,SIGQUIT)){
sigemptyset(&action2.sa_mask);
action2.sa_handler = SIG_DFL;
sigaction(SIGTERM,&action2,NULL);
}
}
}
打开两个终端,在一个终端中执行该程序,在另一个终端中发送信号。
发送信号:kill -SIGINT 进程号
kill -SIGQUIT 进程号
程序运行的结果:

分享到:
相关推荐
### 第9章Linux信号与定时器 #### 一、进程间通信与信号 ...总之,Linux信号和定时器是实现进程间通信和时间管理的关键组件。通过深入理解它们的工作原理和使用方法,开发者可以构建出更加健壮和高效的Linux应用程序。
### Linux信号量、中断与时间管理详解 #### 一、信号量的概念与分类 在Linux系统中,**信号量(Signal)** 是一种重要的进程间通信(IPC)手段,主要用于一个进程向另一个进程发送简短的消息。尽管信号量本身无法携带...
### Linux信号量使用全集解析 #### 一、信号量概览 信号量是一种关键的同步机制,在Linux系统中主要用于管理共享资源的访问,确保在任何时间点只有一个进程(或线程)能够独占资源。当信号量的值为正时,表明资源...
2. **`sigemptyset()`** 和 **`sigfillset()`**:前者初始化信号集为空集,后者初始化信号集包含所有信号。 3. **`sigaddset()`** 和 **`sigdelset()`**:用于向信号集中添加或删除信号。 4. **`sigprocmask()`**:...
linux多任务(进程)同步-信号量集
- **`sigfillset`**:初始化信号集为包含所有信号。 - **`sigaddset`**:向信号集中添加信号。 - **`sigdelset`**:从信号集中删除信号。 - **`sigismember`**:检查信号是否存在于信号集中。 - **`sigprocmask`**:...
linux下多任务的信号量集实现,花了哥两周的时间。
Linux内核通过进程控制块(PCB,即task_struct结构体)来存储关于信号的信息,包括阻塞信号集和未决信号集。阻塞信号集允许进程临时屏蔽某些信号,使其不会立即处理,而是等到解除屏蔽后处理。未决信号集则记录了...
本文将详细讲解Linux C编程中的一种进程间通信方式——信号灯(Semaphore),并结合提供的程序源码进行解析。 信号灯是同步原语之一,它允许进程在执行过程中对某些资源进行互斥访问或同步操作。信号灯由两个基本...
这个讲座深入浅出地讲解了Linux信号量的理论和实践,有助于提升开发者在多进程和多线程环境下的编程能力,更好地理解和解决并发问题。通过学习,我们可以更熟练地利用信号量来保护共享资源,实现高效的并发控制,...
【Linux信号量1】 在多进程环境中,当多个进程需要访问同一共享资源时,可能会出现竞态条件,导致数据不一致。为了解决这个问题,Linux提供了信号量机制,这是一种同步工具,用于协调进程间的访问控制。 信号量是...
综上所述,Linux信号量是解决并发控制问题的重要手段,通过合理的使用信号量,可以有效地避免竞争条件,实现进程间的同步和互斥,从而保证系统的稳定和高效运行。在实际编程中,理解并熟练运用信号量API,可以构建出...
在Linux中,信号量分为两种类型:互斥量(mutex)和信号量集。互斥量是二进制信号量,用于保护临界区,确保同一时间只有一个进程可以访问共享资源。信号量集则可以表示更复杂的计数,允许多个进程同时访问但控制访问...
#### 二、Linux信号灯 在Linux环境下,系统支持的信号灯主要是系统V信号灯。系统V信号灯提供了更为灵活的信号灯操作和管理机制。以下将详细介绍Linux下的系统V信号灯及其相关API。 **系统V信号灯特点:** - **持久...
在Linux操作系统中,信号(Signal)是一种...通过对Linux信号和C语言信号函数的深入理解和实践,可以编写出能够有效响应系统事件和异常的健壮程序。在实际开发中,合理利用信号机制能够增强程序的容错性和可维护性。
在Linux中,信号量可以分为两种类型:整型信号量(互斥锁)和记录型信号量(可以有多个等待进程)。在本实例中,使用的是整型信号量,它用于实现进程互斥。 【进程互斥】进程互斥是指在同一时间只有一个进程可以...
Linux信号量是一种用于进程和线程同步的重要机制,主要用来保护共享资源,确保在任何时刻只有一个进程或线程可以访问特定的资源。信号量的值代表资源的状态,正数表示资源可用,0表示资源被占用,等待其他线程释放。...
Linux C 函数全集是开发者们不可或缺的参考资料,它涵盖了C语言在Linux环境下的众多核心函数,帮助程序员理解和使用这些功能强大的工具。 Linux C 函数全集中,我们可以找到以下主要的知识点: 1. **标准输入/输出...
`semget`用于创建信号量集,`semop`执行信号量操作(如P(等待)和V(释放)操作),`semctl`用于管理信号量集,如初始化或删除。 在实际应用中,信号量常与共享内存结合使用,确保对共享内存的访问是同步的。例如...
- `sigfillset`:初始化信号集包含所有信号。 - `sigaddset`:向信号集中添加信号。 - `sigdelset`:从信号集中移除信号。 - `sigismember`:检查信号是否存在于信号集中。 - `sigprocmask`:设置进程的信号屏蔽集。...