Linux C编程之信号介绍

原创 2012年03月21日 19:43:32
这几天写了CSAPP的实验,用C语言实现一个简单的SHELL,为了做这个实验,把APUE信号相关的内容看了一遍,这里跟大家分享一下。
Unix信号使用总结:

信号的原理:

信号是一种进程通信的方法,他应用于异步事件的处理。信号的实现是一种软中断。它被发送为一个正在运行的进程,已告知进程某个事件发生了。

1.1 信号的创建:

用信号处理来模拟操作系统的中断功能。要想使用信号处理功能,你要做的就是填写一个信号处理函数即可。

(1)调用signal函数

函数原型如下:void signal(int signo,void * handler); signo是信号类型,后面是信号处理函数。

(2)调用kill函数

可以封装一个发送信号的函数:
int send_signal(pid_t pid, int sig) {
    if (kill(pid, sig) < 0) {
        /* fail silently if pid doesn't exist -- this keeps handlers that
         are called too close together from complaining */
        if (errno != ESRCH)
            unix_error("send_signal: kill failed");
    }
    return 0;
}


通过kill函数,对pid进程发送信号

(3)使用sigaction函数封装signal

sigaction的结构如下:

struct sigaction

{

     void(*sa_handler)(int);

     void(*sa_sigaction)(int,siginfo_t *,void *);

     sigset_tsa_mask;

     intsa_flags;

}



可以通过设置sigaction中的参数值获得对sinal的封装。

1.2信号集操作
(1)信号集的概念
在实际的应用中一个应用程序需要对多个信号进行处理,为了方便,linux系统引进了信号集的概念。信号集用多个信号组成的数据类型sigset_t.可用以下的系统调用设置信号集中所包含的数据。在系统中是这样定义的:


typedef struct {     unsignedlong sig[_NSIG_WORDS];} sigset_t;

(2)信号集的操作

信号集的操作

有以下几种:

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigadd(sigset_t *set,int setnumber);

int sigdelset(sigset_t *set,int setnumber);

int sigismember(sigset_t *set,int setnumber);


使用方法:
通常使用sigemptyset函数初始化信号集,然后调用sigadd添加需要处理的信号,这样才能对信号进行阻塞等操作。

(3)信号的阻塞

有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数。这种情况是通过阻塞信号实现的。阻塞的

概念和忽略信号是不同的。操作系统在信号被进程解除阻塞之前不会讲信号传递出去,被阻塞的信号也不会影响进程的行为,信号只是暂时被阻止传递。当进程忽略一个信号

时,信号会被传递出去但进程会将信号丢弃。需要注意当信号被阻塞的时候,如果这种信号发生了多次,在阻塞完成之后,只调用一次这种信号,在阻塞过程中,这种信号是

未决的。
信号阻塞处理涉及到以下几个函数:
1.sigprocmask函数
int sigprocmask(ubt how,const sigset_t*set,sigset_t *oldset);

sigprocmask设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞)。

参数:

how:用于指定信号修改的方式,可能选择有三种

SIG_BLOCK//将set所指向的信号集中包含的信号加到当前的信号掩码中。即信号掩码和set信号集进行或操作。

SIG_UNBLOCK//将set所指向的信号集中包含的信号从当前的信号掩码中删除。即信号掩码和set进行与操作。

SIG_SETMASK //将set的值设定为新的进程信号掩码。即set对信号掩码进行了赋值操作。

set:为指向信号集的指针,在此专指新设的信号集,如果仅想读取现在的屏蔽值,可将其置为NULL。

oldset:也是指向信号集的指针,在此存放原来的信号集。可用来检测信号掩码中存在什么信号。

返回说明:

成功执行时,返回0。失败返回-1,errno被设为EINVAL。

2.sigsuspend函数

int sigsuspend(const sigset_t *sigmask);

此函数用于进程的挂起,sigmask指向一个信号集。当此函数被调用时,sigmask所指向的信号集中的信号将赋值给信号掩码。之后进程挂起。直到进程捕捉到信号,

并调用处理函数返回时,函数sigsuspend返回。信号掩码恢复为信号调用前的值,同时将errno设为EINTR。进程结束信号可将其立即停止。

3.sigpending函数

次函数是判断当前信号是否处于未决状态

1.3 wait()和waitpid()
wait和waitpid是处理僵死进程的函数,一般通过在while循环中使用这两个函数来处理僵死进程。

实例:

前面介绍了这么多关于信号的东西,下面看一个实例:

#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "signal.h"

char *id = "terminal\n";
int count = 0;

static void do_termal(int sig) {
    ++count;
    //write(1,id,strlen(id));
    printf("aaaaa\n");
}

static void do_stop(int sig) {
    ++count;
    //write(1,id,strlen(id));
    printf("stop\n");
}
int main() {
    struct sigaction sa_oact;
    struct sigaction sa_nact;
    sigset_t pendmask;

    sa_nact.sa_handler = do_termal;
    sa_nact.sa_flags = 0;
    sigemptyset(&sa_nact.sa_mask);
    sigaddset(&sa_nact.sa_mask, SIGTSTP);
    sigprocmask(SIG_BLOCK, &sa_nact.sa_mask, &sa_nact.sa_mask);
    sigaction(SIGINT, &sa_nact, &sa_oact);
    sa_nact.sa_handler = do_stop;
    sa_nact.sa_flags = 0;
    sigaction(SIGTSTP, &sa_nact, &sa_oact);
    puts("sig!");
    do {
        if (count == 2) {
            sigprocmask(SIG_UNBLOCK, &sa_nact.sa_mask, &sa_nact.sa_mask);
            printf("un_block ctrl_z\n");
        }
        sigpending(&pendmask);
        if (sigismember(&pendmask, SIGTSTP)) {//SIGINT是悬而未决的。所谓悬而未决,是指SIGQUIT被阻塞还没有被处理
            printf("SIGTSTP pending\n");
        }
        sleep(2);
    } while (count < 5);
    puts("end");
    return 0;
}




代码中注册了两个信号处理函数,为ctrl_z,和ctrl_c处理,首先初始化sigaction结构中的各个成员,然后调用

sigemptyset(&sa_nact.sa_mask);
sigaddset(&sa_nact.sa_mask, SIGTSTP);

初始化信号集,之后在count<=2的时候对ctrl_z block,当count>2解除block,程序运行中,如果在<2时,多次按ctrl_z,在unblock之后,只会执行一次ctrl_z处理
函数,其余的信号则被抛弃。




相关文章推荐

【Linux】进程间通信-信号量详解及编程实例

前面一篇文章线程同步之信号量同步 讲的是线程之间的信号量,这篇讲的更加具有通用性,能够实现进程之间的同步。 信号量概述 信号量定义: 它是一个特殊变量,只允许对它进行等待和发送信号这...

Linux下C语言开发(信号signal处理机制)

信号signal处理是Linux程序的一个特色,用信号处理来模拟操作系统的中断功能,对于系统程序员来说是最好的一个选择了。同样信号处理也是Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概...

Linux信号编程实践(一) 信号概述

中断     中断是系统对于异步事件的响应, 进程执行代码的过程中可以随时被打断,然后去执行异常处理程序;     计算机系统的中断场景:中断源发出中断信号 -> CPU判断中断是否屏蔽以及保护现...
  • NK_test
  • NK_test
  • 2015年09月15日 20:59
  • 1344

linux下C 信号集处理函数

sigset_t  为信号集 可 sizeof(sigset_t) 查看  128K int sigemptyset(sigset_t * set) 清空设置 ...
  • ebw123
  • ebw123
  • 2016年01月19日 22:53
  • 549

Linux信号相关笔记

最近又温习了一遍Linux中的信号知识,发现有很多东西以前没有注意到,就通过这篇博客记录一下,巩固一下知识点。 信号基础: 信号是什么?为了回答这个问题,首先要从异常说起,这里的异常不是指c+...

Qt singal 机制与调试错误技术(转载)

QT是一个跨平台的C++ GUI应用构架,它提供了丰富的窗口部件集,具有面向对象、易于扩展、真正的组件编程等特点,更为引人注目的是目前Linux上最为流行的KDE桌面环境就是建立在QT库的基础之上。Q...

用C++在Windows上开发SNMP扩展代理(SNMP extension agent) DLL

9月接到一个开发任务,做一个SNMP代理软件和第三方网管软件对接。

Linux C编程--进程间通信(IPC)3--信号集和发送信号介绍

Linux信号集   1.信号集概念   信号集是一个能表示多个信号的数据类型,sigset_t set ;set即一个信号集。   既然是一个集合,就需要对集合进行添加/删除等操作...

Linux C编程--进程间通信(IPC)3--信号集和发送信号介绍

Linux信号集   1.信号集概念   信号集是一个能表示多个信号的数据类型,sigset_t set ;set即一个信号集。   既然是一个集合,就需要对集合进行添加/删除等操作...

Linux C编程--进程间通信(IPC)2--信号处理函数

本文将对两个信号处理函数进行介绍 1.signal 2.sigaction 1.signal signal(设置信号处理方式) 相关函数  sigaction,kill,rai...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux C编程之信号介绍
举报原因:
原因补充:

(最多只允许输入30个字)