进程间通信——信号

进程间通信——信号


宗旨:技术的学习是有限的,分享的精神是无限的。


一、信号和中断

1、信号基本概念

(1)发送信号:产生信号,有多种发送信号的方式【一个进程到另一个进程,内核向用户,进程向自己】

(2)安装信号:设置信号到来时不再执行默认操作,而是执行自定义的代码。

(3)递送信号:一个信号被操作系统发送到目标进程引起某段处理程序的执行。

(4)捕获信号:被递送的信号在目标进程引起某段处理程序的执行。

(5)屏蔽信号:进程告诉操作系统暂时不接受某些信号。

(6)忽略信号:进程被递送到目标进程,但目标进程不处理,直接丢弃。

(7)未决信号:信号已经产生,但因目标进程暂时屏蔽该信号而不能被目标进程捕获到的信号。

(8)可靠信号和不可靠信号:编号小于32的信号是不可靠信号,大于32的是可靠信号。

     信号的“未决”是一种状态,指的是从信号的产生到信号被处理前的这一段过程。信号的“屏蔽”是一个开关动作,指的是暂时阻止该信号被处理。

输入命令kill –l查看系统定义的信号列表:

$ kill-l

 1) SIGHUP      2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP

 6) SIGABRT     7) SIGEMT       8) SIGFPE       9) SIGKILL     10) SIGBUS

11)SIGSEGV     12) SIGSYS      13) SIGPIPE     14) SIGALRM     15) SIGTERM

16)SIGURG      17) SIGSTOP     18)SIGTSTP     19) SIGCONT     20) SIGCHLD

21)SIGTTIN     22) SIGTTOU     23) SIGIO       24) SIGXCPU     25) SIGXFSZ

26)SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGPWR      30) SIGUSR1

31)SIGUSR2     32) SIGRTMAX

 

二、发送信号

        发送信号是指一个进程向另一个进程发送某个信号值,但实际并不是直接发送的,而是由OS转发的。产生一个信号有多种情况:

(1) 用户按下Ctrl-C,这个键盘输入产生一个硬件中断。

(2) 硬件异常产生信号。对一个无效存储访问的进程产生一个SIGSEGV

(3) 终止进程信号。其他进程调用kill()函数可将信号发送给另一个进程或进程组。

(4) 软件异常产生信号。

1、kill发送一个信号到进程

        ——传递一个信号给指定进程使用kill()函数,给当前进程使用raise(),唤醒设置定时使用alarm()

(1)函数原型

#include<signal.h>

intkill(pid_t pid, int sig);

(2)函数参数

       pid:要被传递信号的进程号(PID)

              pid>0:将信号发送给进程的PID值为pid的进程

              pid=0:将信号发送给和当前进程在同一进程组的所有进程

              pid=-1:将信号发送给系统内的所有进程

              pid<0:将信号发送给进程组号PGID为pid绝对值的所有信号

       sig:发送的信号值

(3)返回值

       成功返回0,失败返回-1

       可向某个进程发送kill -0信号以检测进程是否存在,因为当前进程总是存在的:

       kill(getpid, 0);

 

2、raise自举一个信号

        ——给当前进程发送一个信号,即唤醒一个进程。

(1)函数原型

       #include <signal.h>

       int raise(int sig);

(2)函数参数

       sig:发送的信号值

(3)返回值

       成功返回0,失败返回-1

       此函数相当于:

if(kill(getpid(),sig) == -1)

{

  perror(“raise”);

}

 

3、alarm定时

        ——传递定时信号,即在多少时间内产生SIGALRM信号,调用一次产生一个信号。

(1)函数原型

       #include <unistd.h>

       int alarm(unsigned int seconds);

(2)函数参数

       seconds:多少时间内发送SIGALRM信号给当前进程

              seconds=0:取消所有发出的报警请求

(3)返回值

       在调用alarm之前没有调用过alarm,成功返回0,失败返回-1;

       此前调用过alarm函数,则将重新设置调用进程的闹钟,成功,将以当前时间为基准,返回值为上次设置的alarm将在多少时间内产生SIGALRM信号。

 

4、ualarm定时

        ——使当前进程在指定时间内产生SIGALRM信号,然后每隔指定时间重复产生SIGALRM信号。

(1)函数原型    

       useconds_t ualarm(useconds_t value,useconds_t interval);

(2)函数参数

       value:指定时间(us)内产生SIGALRM信号

interval:每隔指定时间重复产生SIGALRM

(3)返回值

       成功返回0,

三、安装信号和捕捉信号

1、信号处理方法

(1) 忽略此信号。

(2) 执行该信号的默认处理动作。

(3) 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方 式称为捕捉(Catch)一个信号。

2、signal安装信号

——信号都有默认的处理方式,未做特殊处理,将执行默认操作;若要做特殊处理,则要安装信号处理函数。

(1)函数原型

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int sig, sighandlerhandler);

(2)函数参数

       sig:接收到的信号

       handler:接收到此信号后的处理代码入口

(3)返回值

       成功返回指向针对此信号的上一次设置,执行失败返回SIG_EER(-1)错误。

3、sigaction安装信号

        ——signal只能提供简单的信号安装操作,并逐步并淘汰。此函数可用来检查和更改信号处理操作。

(1)函数原型

#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);struct sigaction
{void (*sa_handler)(int);/* addr of signal handler, *//* or SIG_IGN, or SIG_DFL*/sigset_t sa_mask; /*additional signals to block */int sa_flags; /* signaloptions, Figure 10.16 *//* alternate handler */void (*sa_sigaction)(int, siginfo_t *, void *);
};

(2)函数参数

       signo:指定信号的编号

       若act指针非空,则根据act修改该信号的处理动作。若oact指针非 空,则通过oact传出该信号原来的处理动作。

(3)返回值

       成功返回0,失败返回-1。

        将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默 认动作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函 数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以 用同一个函数处理多种信号。显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用。

        当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返 回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么它会被阻塞到当前处理结束为止。如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返 回时自动恢复原来的信号屏蔽字。 sa_flags字段包含一些选项,我把sa_flags设为0, sa_sigaction是实时信号的处理函数。 

四、信号集操作

信号忽略:系统仍然传递该信号,指示相应进程对该信号不做任何处理。

信号屏蔽:即使传递信号给该进程,该进程也不捕捉信号。

#define SIGSET_NWOEDS (1024 / (8 * sizeof(unsigned long int)))typedef struct
{unsigned long int val[SIGSET_NWOEDS];
} sigset_t;

1、sigprocmask

         ——设置进程屏蔽信号集

(1)函数原型

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

(2)函数参数

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

SIG_BLOCK

set包含了我们希望添加到当前信号屏蔽字的信号,相当 于mask=mask|set

SIG_UNBLOCK

set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当 于mask=mask&~set

SIG_SETMASK

设置当前信号屏蔽字为set所指向的值,相当于mask=set

 

(3)返回值

       若成功则为0,若出错则为-1

 

2、sigpending

#include <signal.h>
int sigpending(sigset_t *set);

        ——读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

#include<signal.h>
#include<stdio.h>
#include<unistd.h>void printsigset(const sigset_t *set)
{int i;for (i = 1; i < 32; i++)if (sigismember(set, i) == 1){putchar('1');}else{putchar('0');}puts("");
}int main(void)
{sigset_t s, p;sigemptyset(&s);sigaddset(&s, SIGINT);sigprocmask(SIG_BLOCK, &s, NULL);while (1){sigpending(&p);printsigset(&p);sleep(1);}return 0;
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

3、信号集

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

        函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。注意,在使用sigset_t类型的变量之前,一定要调用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。这四个函数都是成功返 回0,出错返回-1。 sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。

 

五、等待信号

        进程可以因等待某些特定的信号而阻塞,pause()函数用来等待除当前进程外的任意信号,而sigsuspend()用来等待指定信号以外的任意信号。

1pause

        ——使调用进程挂起直到有信号递达

(1)函数原型

#include <unistd.h>
int pause(void);

(2)参数返回值

       如果信号的处理动作是终止进程,则进程终止, pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态, pause不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1, errno设置为EINTR, 所以pause只有出错的返回值。

// 用alarm和pause实现sleep(3)函数
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_alrm(int signo)
{/* nothing to do */
}
unsigned int mysleep(unsigned int nsecs)
{struct sigaction newact, oldact;unsigned int unslept;newact.sa_handler = sig_alrm;sigemptyset(&newact.sa_mask);newact.sa_flags = 0;sigaction(SIGALRM, &newact, &oldact);alarm(nsecs);pause();unslept = alarm(0);sigaction(SIGALRM, &oldact, NULL);return unslept;
}
int main(void)
{while(1){mysleep(2);printf("Two secondspassed\n");}return 0;
}

(1) main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数sig_alrm。

(2) 调用alarm(nsecs)设定闹钟。

(3) 调用pause等待,内核切换到别的进程运行。

(4) nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程。

(5) 从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数 是sig_alrm。

(6) 切换到用户态执行sig_alrm函数,进入sig_alrm函数时SIGALRM信号被自动屏蔽,从sig_alrm函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入 内核,再返回用户态继续执行进程的主控制流程( main函数调用的mysleep函数)。

(7)pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理。

 

可重入函数——如果一个函数符合以下条件之一则是不可重入的:

调用了malloc或free,因为malloc也是用全局链表来管理堆的。

调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。

【通俗说:使用了全局变量的都是不可重入的】       

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/466719.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转] 关于 WCF 中数据压缩的几篇文章

原文:http://www.cnblogs.com/jiabao/archive/2007/12/04/982534.html在.net3.0出现以前我们进行分布式开发式有两个选择一个是webservice&#xff0c;另一个是remoting&#xff1b;在早期的项目中&#xff0c;比较喜欢remoting&#xff0c;因为remoting可控性好&#xff0c;也…

聊一聊我自己的从业经历和感悟

嵌入式学习&#xff0c;是一个很枯燥的过程&#xff0c;我记得在学习三极管的时候&#xff0c;我真的对这个东西一点感觉都没有&#xff0c;我知道三极管可以放大&#xff0c;然后电子从一个地方去到了另一个地方&#xff0c;然后就触发了某个开关&#xff0c;就发了大水。然后…

gmake与make的区别

gnu make在linux下一般是叫make但是如果是在其他的unix系统下&#xff0c;因为有一个原生的makegnu make就改个名字叫gmake了。就这们简单当port一个老的unix程序&#xff0c;如老的SunOS上的程序时往往需要sed s/gmake/make/ggmake是GNU Make的缩写。Linux系统环境下的make就是…

大数据——sqoop操作mysql和hive导出导入数据

1.sqoop安装 &#xff08;1&#xff09;下载CDH版本的sqoop &#xff08;2&#xff09;解压并进行环境配置 环境变量为&#xff1a; export SQOOP_HOME/home/sqoop-1.4.6-cdh5.15.1 export PATH$PATH:$SQOOP_HOME/bin 在sqoop安装目录/conf/下&#xff1a; #新建sqoop-en…

LinuxC高级编程——线程

LinuxC高级编程——线程 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 一、线程基础 main函数和信号处理函数是同一个进程地址空间中的多个控制流程&#xff0c;多线程也是如 此&#xff0c;但是比信号处理函数更加灵活&#xff0c;信号处理函数的控制…

来自专业的RIA咨询strechmedia机构提供的Flex组件

具体内容见这里&#xff0c;其中最有用的是chart range selection组件&#xff0c;可以用作历史数据浏览和分析&#xff0c;不光能用slider来选择查看的范围&#xff0c;还能控制范围的大小&#xff0c;而且通过图形也能对range selection进行反向操作&#xff0c;非常酷&#…

年终了,肿一下

也没有没有跟大家好好唠唠&#xff0c;一年时间过得飞快&#xff0c;我还记得那时候从老家开车来深圳&#xff0c;一路狂奔&#xff0c;在广西入境广东的时候&#xff0c;因为疫情排查&#xff0c;我们在那里堵了3个小时&#xff0c;还因为路途颠簸&#xff0c;车子一起一停&am…

大数据——spark安装部署和python环境配置

需要配置多台服务器&#xff0c;实验环境&#xff1a;master和data两台服务器&#xff0c;已安装好hadoop&#xff0c;可参考前文&#xff01;&#xff01;&#xff01; 1.spark安装 master安装 &#xff08;1&#xff09;下载scala和spark &#xff08;2&#xff09;解压并…

LinuxC高级编程——线程间同步

LinuxC高级编程——线程间同步 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 1、 互斥锁mutex 多个线程同时访问共享数据时可能会冲突。对于多线程的程序&#xff0c;访问冲突的问题是很普遍的&#xff0c;解决的办法是引入互斥锁&#xff08;Mutex&a…

2021年,这是你们收到的第一份礼物

一、 前言大家好&#xff0c;2020年就要过去了&#xff0c;这一年来&#xff0c;感谢大家对公众号的支持&#xff0c;但是感谢不能停留在嘴上&#xff0c;所以&#xff0c;这次邀请了正点原子赞助。一起给大家送点礼品&#xff01;作为一名 电子/嵌入式 人&#xff0c;正点原子…

SQL SERVER自定义函数

SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- -- Author: captain -- Create date: 2008.05.05 -- Description: 删除垃圾代码 -- ALTER FUNCTION [fzdongmancn].[fun_deleteLj] ( old varchar(1000) ) RETURNS varchar(1000) AS BEGIN declare ind…

Python参考手册(第4版)pdf

下载地址&#xff1a;网盘下载内容简介 本书是权威的Python语言参考指南&#xff0c;内容涉及核心Python语言和Python库的最重要部分。本书内容简洁扼要、可读性强&#xff0c;书中还包括了一些没有在Python官方文档或其他资料中出现过的一些高级的主题。这一版在内容上进…

大数据学习-python通过Pyhive连接hive数据库

1.hbase和hive结合 &#xff08;1&#xff09;hbase建表添加数据 #test是表名&#xff0c;name是列族 #hbase可以一个列族里边多个字段 create test,name#添加数据 put test,1,name:t1,1 put test,1,name:t2,2#查询 scan test#查询 get 表名&#xff0c;row-key&#xff0c;列…

深入理解Linux内核进程上下文切换

在原作者基础上修改了些文字描述&#xff0c;让文章更加通俗易懂作者简介韩传华&#xff0c;就职于南京大鱼半导体有限公司&#xff0c;主要从事linux相关系统软件开发工作&#xff0c;负责Soc芯片BringUp及系统软件开发&#xff0c;乐于分享喜欢学习&#xff0c;喜欢专研Linux…

Linux C高级编程——网络编程基础(1)

Linux高级编程——BSD socket的网络编程 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 一网络通信基础 TCP/IP协议簇基础&#xff1a;之所以称TCP/IP是一个协议簇&#xff0c;是因为TCP/IP包含TCP 、IP、UDP、ICMP等多种协议。下图是OSI模型与TCP/IP模…

使用SQLDMO中“接口SQLDMO.Namelist 的 QueryInterface 失败”异常的解决方法

SQLDMO&#xff08;SQL Distributed Management Objects&#xff0c;SQL分布式管理对象&#xff09;&#xff0c;它封装 Microsoft SQL Server 数据库中的对象。它允许我们通过COM对象&#xff0c;对SQLServer进行管理。SQLDMO对象来自SQLDMO.dll。因为SQLDMO.dll是一个COM对象…

GetKeyState(), GetAsyncKeystate(), GetKeyboardSlate()

GetKeyState、GetAsyncKeyState、GetKeyboardState函数的差别&#xff1a; 1、BOOL GetKeyboardState( PBYTE lpKeyState );获得全部的256个键&#xff08;键盘按键、鼠标按键等等&#xff09;的状态&#xff0c;lpKeyState是指向一个256bit的数组。存放全部键的状态。 2、SHOR…

你月薪多少?

今天跟一个读友聊天&#xff0c;他刚毕业没多久&#xff0c;在一家方案公司上班&#xff0c;月薪6.5&#xff0c;做的Android 开发&#xff0c;用RK方案&#xff0c;有时候也需要做MCU相关的开发&#xff0c;事情多&#xff0c;压力也不少&#xff0c;而且不是双休&#xff0c;…

cx_Oracle安装出现的问题

1.安装cx_Oracle &#xff08;1&#xff09;在线安装 pip install cx_Oracle &#xff08;2&#xff09;源码安装 下载源码&#xff1a;https://pypi.org/project/cx-Oracle/ tar -zxvf cx_Oracle-8.1.0.tar.gz cd cx_Oracle-8.1.0 python setup.py install 2.测试 impo…

凡事想开,心情不坏~

制芰荷以为衣兮&#xff0c;集芙蓉以为裳。 不吾知其亦已兮&#xff0c;苟余情其信芳。 高余冠之岌岌兮&#xff0c;长余佩之陆离。 芳与泽其杂糅兮&#xff0c;唯昭质其犹未亏。 忽反顾以游目兮&#xff0c;将往观乎四荒。 佩缤纷其繁饰兮&#xff0c;芳菲菲其弥章。 民生各有…