源地址:http://blog.csdn.net/jmy5945hh/article/details/7529651

linux间进程通信的方法在前一篇文章中已有详细介绍。http://blog.csdn.net/jmy5945hh/article/details/7350564

本篇详细介绍及代码测试第二种方式,即信号(Signal)。

1 信号简介

信号全称为软中断信号,主要用于进程控制。

信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。

信号的来源包括硬件来源与软件来源。

生存周期从被创建开始,到进程接收到信号。某些情况下允许信号排队。

内核对信号的处理机制:

(1)发送信号的方法为在进程所在的进程表项的信号域设置对应于该信号的位。

(2)睡眠进程的睡眠优先级高于信号时,信号不会唤醒进程。

(3)内核处理信号的时机是进程从内核态返回用户态时或者进程要切换到低优先级睡眠态时。

(4)处理方法:退出,忽略或通过signal函数调用用户定义函数处理。

典型应用:LINUX下程序在命令行运行时,按下CTRL+C将向程序发送SIGINT信号,强制进程结束。

在命令行使用kill -l命令可以列出所有LINUX系统支持的信号

值得注意的是,信号的编号不是连续的。在SIGRTMIN之前的信号被称为不可靠信号,之后的称为可靠信号。

主要的区别在于,不可靠信号:

1/进程每次处理信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调用signal(),重新安装该信号。

2/不支持排队,信号可能丢失。 因此,早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。

2 信号的处理

注册处理函数

  1. #include <signal.h>
  2. void (*signal (int signum, void (*handler) (int) ) ) (int);
  3. /* 等效形式 */
  4. typedef void(*sighandler_t) (int);
  5. sighandler_t signal(int signum, sighandler_t handler);
#include <signal.h>
void (*signal (int signum, void (*handler) (int) ) ) (int);
/* 等效形式 */
typedef void(*sighandler_t) (int);
sighandler_t signal(int signum, sighandler_t handler);

成功返回之前的处理信号配置;出错返回SIG_ERR。

不能捕捉SIGKILL或者SIGSTOP信号。handler取值为SIG_IGN表示忽略,为SIG_DFL表示执行系统默认操作,为函数名时表示执行特定操作。

处理函数增强版

  1. #include <signal.h>
  2. int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

成功后返回0;出错返回-1。

  1. struct sigaction
  2. {
  3. void (*sa_sighandler) (int);
  4. void (*sa_sigaction) (int, siginfo_t *, void *);
  5. sigset_t sa_mask;
  6. int sa_flags;
  7. void (*sa_restorer) (void);
  8. }
struct sigaction
{
void (*sa_sighandler) (int);
void (*sa_sigaction) (int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer) (void);
}

sa_flags参数

取值  含义
SA_NOCLDSTOP 用于指定信号SIGCHLD。
SA_NOCLDWAIT 对信号SIGCHLD,子进程结束时,不创建僵死进程。
SA_NODEFER 处理信号时如果产生了其他信号,则先去处理其他信号。
SA_NOMASK 与SA_NODEFER相似。
SA_RESETHAND 处理完信号后,注销处理函数。
SA_ONESHOT 同SA_RESETHAND相似
SA_RESTART 信号发生时正处在程序阻塞处,则处理完信号从阻塞处返回。
SA_SIGINFO 指示sa_sigaction有效。不设置表示sa_handler有效。

信号集

  1. #include <signal.h>
  2. int sigemptyset( sigset_t *set );
  3. int sigfillset( sigset_t *set );
  4. int sigaddset( sigset_t *set, int signum );
  5. int sigdelset( sigset_t *set, int signum );
  6. int sigismember( const sigset_t *set, int signum );
#include <signal.h>
int sigemptyset( sigset_t *set );
int sigfillset( sigset_t *set );
int sigaddset( sigset_t *set, int signum );
int sigdelset( sigset_t *set, int signum );
int sigismember( const sigset_t *set, int signum );

前四个函数成功返回0;出错返回-1.最后一个函数为真返回1;为假返回0。

信号集用于表示由多个信号所组成的数据类型。empty置空,fill置满,add添加,del删除,member检测。

3 信号的发送

向其他进程发送信号

  1. #include <signal.h>
  2. #include <sys/types.h>
  3. int kill( pid_t pid, int signum );
#include <signal.h>
#include <sys/types.h>
int kill( pid_t pid, int signum );

成功后返回0;出错返回-1。发送对象可以使一个进程组。

向本进程发送信号

  1. #include <signal.h>
  2. #include <sys/types.h>
  3. int raise( int signum );
#include <signal.h>
#include <sys/types.h>
int raise( int signum );

成功后返回0;出错返回-1。

实时信号的发送

  1. #include <signal.h>
  2. #include <sys/types.h>
  3. int sigqueue( pid_t pid, int signum, const union sigval val );
#include <signal.h>
#include <sys/types.h>
int sigqueue( pid_t pid, int signum, const union sigval val );
  1. typedef union sigval
  2. {
  3. int sival_int;
  4. void *sigval_ptr; // 指向要传递的信号参数
  5. } sigval_t;
typedef union sigval
{
int sival_int;
void *sigval_ptr; // 指向要传递的信号参数
} sigval_t;

支持信号带有参数。成功后返回0;出错返回-1。发送对象只能是单个进程。

指定时间的发送

  1. #include <unistd.h>
  2. unsigned int alarm( unsigned int seconds );
#include <unistd.h>
unsigned int alarm( unsigned int seconds );

seconds参数指定了下一次发送SIGALRM信号的时间。如果调用前设置了闹钟,则返回闹钟剩余时间,否则返回0。

  1. #include <sys/time.h>
  2. int setitimer( int which, const struct itimerval *value, struct itimerval *oldvalue);
  3. struct itimerval
  4. {
  5. struct timeval it_interval;
  6. struct timeval it_value;
  7. };
#include <sys/time.h>
int setitimer( int which, const struct itimerval *value, struct itimerval *oldvalue); struct itimerval
{
struct timeval it_interval;
struct timeval it_value;
};

which参数

取值 定时器类型 信号
ITIMER_REAL 根据系统时间设定绝对时间。 SIGALRM
ITIMER_VIRTUAL 设定程序执行时间,用户模式下可跟踪。 SIGVTALRM
TIMER_PROF 从用户进程开始后开始计时。 SIGPROF

成功后返回0;出错返回-1。相比于alarm,setitimer支持三种类型的定时器。

3 信号的阻塞

  1. #include <signal.h>
  2. int sigprocmask( int how, const sigset_t *set, sigset_t *oldset );
#include <signal.h>
int sigprocmask( int how, const sigset_t *set, sigset_t *oldset );

how参数

取值 功能
SIG_BLOCK 将set信号集的信号与掩码做逻辑或运算
SIG_UNBLOCK 将set信号集的信号与掩码做逻辑减运算
SIG_SETMASK 以set信号集对信号掩码进行赋值操作

成功后返回0;出错返回-1。用于信号的阻塞延迟处理。

  1. #include <signal.h>
  2. int sigsuspend( const sigset_t *sigmask );
#include <signal.h>
int sigsuspend( const sigset_t *sigmask );

成功后无返回值;出错返回-1。调用此函数后进程挂起,直到接收到信号复原信号集,然后调用处理函数。

3 信号通信测试代码:

  1. #include <stdio.h>
  2. #include <signal.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. void op(int, siginfo_t*, void*);
  6. int main(int argc,char**argv) {
  7. struct sigaction act;
  8. int sig;
  9. pid_t fpid, spid;
  10. if((spid =fork()) == 0) {
  11. int signum;
  12. union sigval mysigval;
  13. signum = 5; //信号值取5
  14. fpid = getppid(); //获取父进程ID
  15. mysigval.sival_int = 8; // 用于测试
  16. if(sigqueue(fpid, signum, mysigval) == -1) //子进程发送信号
  17. printf("send error\n");
  18. sleep(2);
  19. }
  20. else if(spid > 0) {
  21. struct sigaction act;
  22. int sig = 5;
  23. sigemptyset(&act.sa_mask);
  24. act.sa_sigaction=op;
  25. act.sa_flags=SA_SIGINFO;
  26. if(sigaction(sig, &act, NULL) < 0) //父进程指定对于信号的处理
  27. printf("install sigal error\n");
  28. sleep(2);
  29. }
  30. }
  31. void op(int signum, siginfo_t *info, void *myact) { // 信号处理函数
  32. printf("the int value is %d \n", info->si_int);
  33. }

运行结果:

  1. jimmy@MyPet:~/code/ipc$ gcc -g -o ipc ipc.c
  2. jimmy@MyPet:~/code/ipc$ ./ipc
  3. the int value is 8

非正常测试结果及总结

1)将子进程中的signum改为与父进程中的sig值不一致,不能进行信号通信。

2)信号通信是惟一的进程间异步通信模式。

3)可以在终端输入kill -l查看系统支持的信号。其中前半部分(<=32)是不可靠信号,后半部分是可靠信号。

4)进程对于实时信号的默认处理方式都是终止进程。

转:步步LINUX C--进程间通信(二)信号的更多相关文章

  1. Linux环境进程间通信(二):信号(下)

    linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

  2. Linux环境进程间通信(二): 信号(上)

    linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

  3. <转>Linux环境进程间通信(二): 信号(上)

    原文链接:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html 原文如下: 一.信号及信号来源 信号本质 信号是在软件层 ...

  4. Linux环境进程间通信(二): 信号--转载

    http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html http://www.ibm.com/developerworks ...

  5. [转]Linux进程间通信——使用信号

    转载于:http://blog.csdn.net/ljianhui/article/details/10128731         经典!!! Linux进程间通信——使用信号 一.什么是信号 用过 ...

  6. linux内核剖析(九)进程间通信之-信号signal

    信号及信号来源 什么是信号 信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动.通常信号是由一个错误产生的.但它们还可以作为进程间通信或修改行为的一种方 ...

  7. 练习--LINUX进程间通信之信号SIGNAL

    同样的,信号也不要太迷信可靠信号及不及靠信号,实时或非实时信号. 但必须要了解这些信号之间的差异,函数升级及参数,才能熟练运用. ~~~~~~~~~~~~~~~~ 信号本质 信号是在软件层次上对中断机 ...

  8. Linux进程间通信(三) - 信号

    什么是信号 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间通 ...

  9. 【转载】Linux的进程间通信-信号量

    原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...

随机推荐

  1. php 扫描url死链接 \033[31m ANSI Linux终端输出带颜色

    * 从Packagist上搜索需要的包 https://packagist.org/ * 通过composer下载依赖包 composer require guzzlehttp/guzzlecompo ...

  2. 资源-Java:Java资源列表

    ylbtech-资源-Java:Java资源列表 1. 开发软件返回顶部 1.Eclipse https://www.eclipse.org/ 2.IntelliJ IDEA https://www. ...

  3. day19_生成器

    20180730 初次上传 20180731 更新,4.列表生成式,以及部分注释 #!/usr/bin/env python # -*- coding:utf-8 -*- # ************ ...

  4. 关于type return to continue,or q <return> to quit

    由于GDB要打印的信息被分页了 所以需要设置不分页显示 set pagination off

  5. 第一篇:spring+springMVC项目启动最终笔记(一web.xml)

    1.web应用启动从web.xml开始,首先创建一个全局的上下文(Context),名字叫ServletContext,可以理解为一间图书馆,或一个数据结构(如map,但是比map牛多了),整个结构类 ...

  6. Django的日常-模型层(1)

    目录 Django的日常-模型层(1) 模型层 django测试环境 ORM查询 Django的日常-模型层(1) 模型层 模型层其实就是我们应用名下的models.py文件,我们在里面写入想要创建的 ...

  7. 第二周课堂笔记1th

    1.    三元运算 + 2.      for循环 for为有限循环,while为无限循环 可迭代对象:是字符串,数字不可以 数字不可以迭代但是可以用range函数 for i in range(1 ...

  8. Django中static文件的引入

    1. 在django project中创建 static文件夹 2.settings.py中配置要在 STATIC_URL = '/static/'  下边 STATICFILES_DIRS = [ ...

  9. spring:AOP面向切面编程02

    参考: https://blog.csdn.net/jeffleo/article/details/54136904 一.AOP的核心概念AOP(Aspect Oriented Programming ...

  10. duilib教程之duilib入门简明教程1.前言

    关于duilib的介绍就不多讲了,一来不熟,二来小伙伴们想必已经对比了多个界面库,也无需赘述.下面进入正题:    不看广告看疗效! 已有众多知名公司采用duilib做为界面库,如华为网盘.PPS(P ...