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下C语言开发(信号signal处理机制)

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

unix环境高级编程之信号篇(一)

一、引言: 信号是软件中断,很比较重要的应用程序都需要处理信号。信号提供了一种处理异步事件的方法,例如,中断用户键入中断键,则会通过信号机制停止一个程序,或及早终止管道中的下一个程序。...
  • cgqzly123
  • cgqzly123
  • 2016年01月26日 19:39
  • 689

【Linux C】信号及信号处理

1.        信号是一种异步的进程通信方式,又称为软件中断,进程收到信号后会打断原来的程序执行流程。当进程被调度或者从内核态返回用户态时检查信号。 2.        常见有 ctrl+\产生...
  • roler_
  • roler_
  • 2014年02月25日 22:42
  • 693

传智168期--Linux&LAMP编程之Linux2016版额外笔记(2017年8月25日18:50:55)

学Linux的过程中做的一点点笔记,学了几天。 笔记下载地址:http://download.csdn.net/download/juliantem/9950769 http://download...
  • juliantem
  • juliantem
  • 2017年08月25日 18:50
  • 228

linux编程之信号

信号是Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念、Linux对信号机制的大致实现方法、如何使用信号,以及有关信号的几个系统调用。  信号机制是进程之间相互传递消息的一种方法,信...
  • HandsomeHong
  • HandsomeHong
  • 2017年05月22日 13:36
  • 138

编程之禅 浅谈封装

作为一个整天与代码打交道的人,你真的会coding吗? 今天依旧来反思一下自身。伊始大一的时候,刚接触到了C语言,一门神奇的语言。老师就教导我们要多敲例子,照着书本敲就可以了。可能当时并没有真正的理解...
  • Marksinoberg
  • Marksinoberg
  • 2016年06月17日 10:00
  • 6835

linux系统编程之基础必备(一):计算机体系结构一点基础知识

下面这张图来自《深入理解计算机系统》: IO桥部分一般还分为北桥和南桥,北桥当然是靠上的了。 •CPU –主频: CPU的时钟频率,内核工作的时钟频率 –外频: 系统总线的工作频率 ...
  • Sandeldeng
  • Sandeldeng
  • 2016年10月23日 16:25
  • 228

JDBC编程之程序优化

首先,新建包package com.djx.entity;,其中类为 Identity ,实现代码如下: package com.djx.entity; public abstract class...
  • dengjiaxing0321
  • dengjiaxing0321
  • 2016年03月16日 15:49
  • 129

GPS模块编程之NMEA0183协议

原文地址:http://blog.csdn.net/northcan/article/details/7261310 ########################################...
  • heli200482128
  • heli200482128
  • 2016年06月14日 15:23
  • 368

Linuxc编程之信号

写这篇博客只是在梳理这几天我看到知识。 LinuxC编程比较难,以前没有接触过操作系统理论,不是正统的计算机专业出身。看书看着看着就忘了,这是我第2次看《LinuxC编程一站式学习》。看第一遍的时候...
  • qq_17461615
  • qq_17461615
  • 2015年03月25日 19:37
  • 74
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux C编程之信号介绍
举报原因:
原因补充:

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