进程间通信-IPC._第1页
进程间通信-IPC._第2页
进程间通信-IPC._第3页
进程间通信-IPC._第4页
进程间通信-IPC._第5页
已阅读5页,还剩110页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、linux进程间通信linux进程间通信进程间通信IPC(interprocess Communication)提供了一种不同进程间可以互相访问数据的方式。相互访问的数据不仅包括程序运行时的适时数据,也包括对对方代码段的访问。进程间通信的目的: 1、数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。2、共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。3、通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。4、资源共享:多个进程之间共享同样的资源。为了作到这一点,需要

2、内核提供锁和同步机制。5、进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有异常,并能够及时知道它的状态改变。linux进程间通信发展历史linux进程间通信(IPC)由以下几部分发展而来:linux进程间通信方式目前Linux 中使用较多的进程间通信方式:(1)管道(Pipe)及有名管道(named pipe) :管道可用于具有亲缘关系进程间的通信;有名管道,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。(2)信号(Signal) :信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知接受进程有某事件发

3、生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一样的。(3)消息(message)队列:消息队列是消息的链接表,包括 Posix 消息队列 systemV 消息队列。它克服了前两种通信方式中信息量有限的缺点,具有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读取消息。linux进程间通信(4)共享内存(shared memory) :可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种通信方式需要依靠某种同步机制,如互斥锁和信号量等。(5)信号量(se

4、maphore) :主要作为进程间以及同一进程不同线程之间的同步手段。(6)套接字(Socket) :这是一种更为一般的进程间通信机制,它可用于不同机器之间的进程间通信,应用常广泛。管道通信管道通信是linux 中比较常见,也比较原始的通信方式之一,它实现了数据以一种数据流的方式,在多进程间流动。管道:是指用于连接一个读进程和一个写进程,以实现它们之间通信的共享文件,又称pipe文件。 管道是单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。 写进程在管道的尾端写入数据,读进程在管道的首端读出数据。 数据读出后将从管道中移走,其它读进程都不

5、能再读到这些数据。 管道提供了简单的流控制机制。进程试图读空管道时,在有数据写入管道前,进程将一直阻塞。同样,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。管道分类: 无名管道: (匿名管道)在系统中没有实名,不能在文件系统中以任何方式看到该管道,它只是进程的一种资源,会随着进程的结束而被系统清除。 有名管道:也称为FIFO管道,是一种文件类型,在文件系统中可以查看到。7匿名管道(pipe) 对匿名管道两端进程而言,是一个只存在于内存的特殊文件 匿名管道是半双工的,数据只能向一个方向流动 一个进程将数据写入管道,另一进程从管道中读取数据 写入的内容添加在管道

6、缓冲区的末尾,每次都是从缓冲区头部读出数据 双向通信的建立 需要建立起两个管道 使用限制 只能用于具有亲缘关系的进程之间 如父子进程或兄弟进程之间管道通信管道通信8匿名管道的建立 基本函数 int pipe(int fd2); 参数说明 fd2描述管道两端 fd0只能用于读,称为管道读端 fd1只能用于写,称为管道写端 若试图从写端读,或者向读端写都将导致错误发生 返回值 成功时返回0,失败时返回-1 说明 基本文件I/O函数都可用于管道 如close()、read()、write()等 低层系统调用 sys_pipe( )-do_pipe()管道通信管道通信9匿名管道的读操作 进程调用rea

7、d()系统调用 内核最终调用与该文件描述符相关的文件操作表中所找到的read()方法 在管道情形下,read方法将指向pipe_read()函数 该系统调用可能以两种方式阻塞当前进程 系统调用开始时管道缓冲区为空 管道缓冲区没有包含所请求的字节(n个字节),写进程在等待缓冲区的空间时曾经被置为睡眠10匿名管道的写操作 进程调用write()系统调用 内核最终调用pipe_write()函数 如果管道没有读进程,写进程发送SIGPIPE信号 管道缓冲区一有空闲区域,写进程将试图写入数据 如果读进程不读出管道缓冲区中的数据,那么写操作将一直阻塞匿名管道示例一#include#include#inc

8、ludeint main(void) int fd2; char str256; if( pipe(fd)0 ) perror(pipe); exit(1); write(fd1, Create the pipe successfully!n, 31); read(fd0, str, sizeof(str); printf(%sn,str); close(fd0); close(fd1); return 0; 单个进程中的管道几乎没有任何用处。通常,调用 p i p e的进程接着调用 f o r k,这样就创建了从父进程到子进程或反之的 I P C通道。 f o r k之后做什么取决于我们想要

9、有的数据流的方向。对于从父进程到子进程的管道,父进程关闭管道的读端(f d 0 ) ,子进程则关闭写端(f d 1 ) 。对于从子进程到父进程的管道,父进程关闭 f d 1 ,子进程关闭f d 0 。12#include#include#include#define BUFSZ 256int main(void) int fd2; char bufBUFSZ; pid_t pid; int len; if( pipe(fd)0 ) perror(failed to pipe); exit(1); if( (pid = fork() 0) printf(This is farther, writ

10、e to fd1n,fd0,fd1); close(fd0); write(fd1, farther write,child readn, 25); exit(0); else printf(This is child ,read from fd0n); close(fd1); read(fd0, buf, BUFSZ); printf(%sn, buf); return 0;匿名管道-父子进程间通信匿名管道操作基本流程 管道操作的基本流程:1)使用pipe函数创建管道;2)用fork函数创建一个子进程;3)关闭父子进程中不需要的文件描述符,使用管道进行通信;由于以上对管道的操作是比较规范,也

11、比较常用。所以在ANSI C中将以上操作定义在两个标准库函数中,分别是popen和pclose函数。 FILE * popen(const char * command, const char * type) ; int pclose(FILE * f p) ; 参数command是一个在shell中可以运行的命令字符串的指针; 参数type是一个字符指针,这个参数只有两种值,分别是r和w,分别对应popen函数的返回值是一个读打开文件指针,还是写打开文件指针。函数失败返回NULL,并设置出错变量errno。pclose函数的参数fp是一个popen打开的文件描述符,函数失败时返回-1。#in

12、clude #include #include #include #include #define BUFES PIPE_BUFint main(void) FILE *fp; char *cmd = ls -l; char bufBUFES; if(fp = popen(cmd, r) = NULL) perror(failed to openn); exit(1); while(fgets(buf, BUFES, fp) != NULL) printf(%sn, buf); pclose(fp); exit(0);Popen示例16有名管道 匿名管道缺点 没有名字,只能用于具有亲缘关系的进

13、程间通信 FIFO(有名管道) 严格遵循先进先出的读写规则 有名字,FIFO的名字包含在系统的目录树结构中,支持无亲缘关系的进程按名字访问 类似管道,在文件系统中不存在数据块,而是与一块内核缓冲区相关联 read和write操作也由pipe_read()和pipe_write() 实现 与匿名管道主要区别 FIFO索引节点出现在系统目录树上而不是pipefs特殊文件系统中 FIFO是一种双向通信管道,可以以读/写模式打开一个FIFO17有名管道的建立 基本函数 int mkfifo(const char * pathname, mode_t mode); 参数说明 pathname:创建的FI

14、FO名字 mode:规定FIFO的读写权限 返回值 成功时返回0 失败时返回-1 若路径名存在,则返回EEXIST错误 说明 一般文件的I/O函数都可用于管道,如open(), close(), read(), write()等。18有名管道的open() 打开规则 为读操作而打开FIFO文件 若已有进程为写而打开该FIFO,则当前打开操作将成功返回 否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操作设置未设置O_NONBLOCK标志) 或立即返回(当前打开操作设置O_NONBLOCK标志) 为写操作而打开FIFO文件 如果已经有进程为读而打开该FIFO,则当前打开操作将成功返回

15、否则,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操作未设置O_NONBLOCK标志) 或者,返回ENXIO错误(当前打开操作设置O_NONBLOCK标志) 实例:1,mkfifo testfifo 建立有名管道文件testfifo;2,ls testfifo 向有名管道文件写入”ls”命令显示的内容;3,cat testfifo 用”cat”命令读取”testfifo”文件中的内容;19有名管道示例创建有名管道#include#include#include#include#include#include#include#includeint main(int argc, char*

16、 argv)/mode_t mode = 0666;mode_t mode = O_NONBLOCK;if( argc!=2 ) printf(USEMSG: create_fifo fifonamen); exit(1);if(mkfifo(argv1,mode)0) perror(failed to mkfifo); exit(1);elseprintf(you successfully create a FIFO name is:%sn,argv1);exit(0); 20有名管道举例读有名管道 #include #include #include #include #include #

17、include #include #include #define BUFES PIPE_BUF int main(void) int fd; int len; char bufBUFES; if(fd=open(testfifo,O_RDONLY)0) printf(read: %s,buf); close(fd); return 0; 21有名管道示例写有名管道#include#include#include#include#include#include#include#include#define BUFES PIPE_BUFint main(void) int fd; int n,

18、i; if( (fd=open(testfifo,O_WRONLY) 0) perror(open); exit(1); for(i=0; i10; i+) if ( write(fd,message n,9)0 ) perror(write); exit(1); close(fd); return 0;22信号的本质 信号是一种进程间异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。在实现上是一种软中断。是对中断的模拟,也称软中断信号或软中断。 信号可以导致一个正在运行的进程被异步打断,让进程知道已经发生了一个特定事件; 强迫进程执行自身代码中的信号处理程序; 发给非运行

19、进程的信号必须由内核保存,直到进程恢复执行; 阻塞一个信号要求信号的传递被延迟,直到随后解除阻塞; 每个信号都有名字,这些名字都是以SIG开头; 不存在编号为0的信号。信号来源硬件来源硬件操作,如按Ctrl+C硬件故障软件来源常用信号发送函数,如kill(), raise(), alarm()非法运算(浮点运算溢出或内存访问错误等也可产生信号24信号分类 不可靠信号 信号值小于SIGRTMIN; 进程每次处理信号后,将信号响应函数设置为默认动作,需调用signal() 重新安装信号 ; 非实时信号都是不可靠信号,不支持排队,信号可能丢失; 可靠信号 信号值介于SIGRTMIN和SIGRTMAX

20、之间; 新信号安装函数sigaction()和信号发送函数sigqueue(); 实时信号都是可靠信号,支持排队;信号通信信号通信25进程对信号的响应方式 忽略信号 进程忽略接收到的信号,不做任何处理; SIGKILL和SIGSTOP不能忽略; 不能为SIGKILL和SIGSTOP设置新的信号处理函数。 捕获信号 类似中断处理程序,一旦捕获到相应信号,执行对应的信号处理函数; 进程可通过signal()/sigaction()指定进程对某个信号的处理行为; 缺省操作 Linux内核为信号提供默认处理程序处理;26常见信号1SIGHUP从终端上发出的结束信号从终端上发出的结束信号2SIGINT来

21、自键盘的中断信号(来自键盘的中断信号(Ctrl-c)3SIGQUIT来自键盘的退出信号(来自键盘的退出信号(Ctrl-)8SIGSTOP进程收到该信号后会暂停执行,进入暂停态进程收到该信号后会暂停执行,进入暂停态9SIGKILL立即结束程序,立即结束程序,不能被阻塞不能被阻塞,处理和忽略,处理和忽略14 SIGALRM 进程的定时器到期时,发送该信号进程的定时器到期时,发送该信号18 SIGCONT处于阻塞状态的进程收到该信号后会继续执处于阻塞状态的进程收到该信号后会继续执行行17 SIGCHLD子进程退出时给父进程发送该信号子进程退出时给父进程发送该信号27信号生命周期信号诞生 触发信号的事

22、件发生(如检测到硬件异常、定时器超时以及调用信号发送函数kill()或sigqueue()等)。信号在进程中注册 内核更新目标进程的数据结构,将信号加入进程的未决信号集,并将信号所携信息保存到某个sigqueue结构中 对实时信号,不管其是否已在进程中注册,都被再次注册 对非实时信号,若该信号已在进程中注册,则将其丢弃信号在进程中注销 进程从核心空间返回用户空间时都检测是否有信号等待处理 若存在等待处理且未被阻塞的未决信号,则将其在未决信号链中占有的结构卸掉(对实时进程只删除sigqueue结构)信号处理函数执行完毕 执行相应信号处理函数或改变目标进程的执行状态28信号在进程中注册 进程的ta

23、sk_struct结构中有关于本进程中未决信号的数据成员: struct sigpending中第三个成员signal是进程中所有未决信号集,第一、第二个成员分别指向一个sigqueue类型的链表的(称之为“未决信号信息链”)的首尾,该链中的每个sigqueue结构包含一个特定信号所携带的信息,并指向下一个sigqueue结构:struct sigpending pending;struct sigpendingstruct sigqueue *head, *tail;sigset_t signal;struct sigqueuestruct sigqueue *next;siginfo_t

24、info;信号在进程中注销 在目标进程执行过程中,会检测是否有信号等待处理(每次从系统空间返回到用户空间时都做这样的检查)。如果存在未决信号等待处理且该信号没有被进程阻塞,则在运行相应的信号处理函数前,进程会把信号在未决信号链中占有的结构卸掉。是否将信号从进程未决信号集中删除对于实时与非实时信号是不同的。对于非实时信号来说,由于在未决信号信息链中最多只占用一个sigqueue结构,因此该结构被释放后,应该把信号在进程未决信号集中删除(信号注销完毕);而对于实时信号来说,可能在未决信号信息链中占用多个sigqueue结构,因此应该针对占用sigqueue结构的数目区别对待:如果只占用一个sigq

25、ueue结构(进程只收到该信号一次),则应该把信号在进程的未决信号集中删除(信号注销完毕)。否则,不应该在进程的未决信号集中删除该信号(信号注销完毕)。 进程在执行信号相应处理函数之前,首先要把信号在进程中注销。30信号处理函数 信号发送函数 kill(), sigqueue(), raise(), alarm(), setitimer(), pause(),abort() 信号安装函数 signal(), sigaction() 信号集操作函数 sigemptyset(), sigfillset(), sigaddset(), sigdelset(), sigismember()31信号发送

26、函数kill()#include #include int kill(pid_t pid,int signo) 功能 向进程或进程组发送一个信号 (成功返回 0; 否则,返回 -1 )参数说明 pid:接收信号的进程(组)的进程号 pid0:发送给进程号为pid的进程 pid=0:发送给当前进程所属进程组里的所有进程 pid=-1:发送给除1号进程和自身以外的所有进程 pid-1:发送给属于进程组-pid的所有进程 signo:发送的信号 Signo = 0:不发送信号,可用于检查目标进程是否存在,以及当前进程是否具有向目标进程发送信号的权限(root权限的进程可以向任何进程发送信号,非roo

27、t权限的进程只能向属于同一个session或者同一个用户的进程发送信号)。#include #include #include #include #include int main( void ) pid_t childpid; int status; int retval; childpid = fork(); if ( -1 = childpid ) perror( fork() ); exit( EXIT_FAILURE ); else if ( 0 = childpid ) puts( In child process ); sleep( 100 );/让子进程睡眠,看看父进程的行为

28、exit(EXIT_SUCCESS); else if ( 0 = (waitpid( childpid, &status, WNOHANG ) retval = kill( childpid,SIGKILL ); if ( retval ) puts( kill failed. ); perror( kill ); waitpid( childpid, &status, 0 ); else printf( %d killedn, childpid ); exit(EXIT_SUCCESS); 33信号发送函数sigqueue()#include #include int si

29、gqueue(pid_t pid, int signo, const union sigval sigval_t) 调用成功返回 0;否则,返回 -1。功能 主要针对实时信号,支持带有参数信号,与函数sigaction()配合使用参数说明 pid:接收信号的进程ID signo:待发送信号 sigval_t:信号传递的参数(4字节)说明 调用sigqueue()时,sigval_t被拷贝到信号处理函数 sigqueue()发送非实时信号时 sigval_t包含的信息仍然能够传递给信号处理函数 仍然不支持排队,所有相同信号都被合并为一个信号34sigqueue()向信号传递附加消息的流程 sig

30、queue()的第三个参数是sigval联合数据结构 调用sigqueue()时,该数据结构中的数据将被拷贝到信号处理函数sigaction()的第二个参数 这样,就可在发送信号的同时让信号传递一些附加信息 typedef union sigval int sival_int; void *sival_ptr; sigval_t;35Kill()与sigqueue()区别 sigqueue()比kill()传递更多的附加信息 sigqueue()只能向一个进程发送信号信号通信信号通信36信号发送函数raise()#include int raise(int signo) 功能 向自身发送信号

31、参数说明 signo:发送的信号 signo=0:不发送信号返回值 成功时,返回0 错误时,返回-1说明 raise()可以通过kill( )实现,raise(signo)等价于 kill(getpid( ), signo);信号通信信号通信 #include #include int main(void) printf(kill myself!n); raise(SIGKILL); printf(can you see this?n); return 0; 38信号发送函数alarm()#include unsigned int alarm(unsigned int seconds) 功能

32、设置定时器,当计时时间到达时,向进程发出SIGALRM信号参数说明 seconds:等待秒数 seconds为0时,取消先前设置的闹钟,返回闹钟剩余时间u若之前未设闹钟,则返回0说明 alarm()只发送一次信号 若需重复设定定时器,则要多次调用alarm()函数 信号通信信号通信#include #include #include #include #include void handler() printf(hellonn);main()int i;signal(SIGALRM,handler);alarm(5);for(i=1;i7;i+)printf(sleep %d n,i);sle

33、ep(1);40信号发送函数setitimer()函数原型 int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue); 参数说明 which:逻辑定时器类型 ITIMER_REAL:按实际时间计时,计时到达时向进程发送SIGALRM信号。 ITIMER_VIRTUAL:计算进程在用户态执行的时间,计时到达将发送SIGVTALRM信号给进程。 ITIMER_PROF:计算进程在用户态和核心态的总时间。计时到达将发送SIGPROF信号给进程。u与ITIMER_VIRTUAL是一对,该定时器经常

34、用来统计进程在用户态和核心态花费的时间 value:指明定时器的时间 ovalue:如果不为空,则保存上次调用设定的值功能 指定一段时间后,执行某个function; 每间格一段时间就执行某个function41信号发送函数setitimer() (续)返回值 成功时,返回0 错误时,返回-1struct itimerval结构定义struct itimerval struct timeval it_interval; /*定时器周期*/ struct timeval it_value; /*定时器剩的时间,为0时发信号*/; struct timeval结构定义struct timeval

35、long tv_sec; /*秒*/ long tv_usec; /*微秒,1秒=1000000微秒*/; it_value为为0是不会触发信号的,所以要能触发信号,是不会触发信号的,所以要能触发信号,it_value得大于得大于0;如果如果it_interval为零,只会延时,不会定时(也就是说只会触发一次信为零,只会延时,不会定时(也就是说只会触发一次信号号)。信号通信信号通信42信号发送函数setitimer()示例 #include #include #include void signalHandler(int signo) switch (signo) case SIGALRM:

36、printf(Caught the SIGALRM signal!n); break; int main(int argc, char *argv) signal(SIGALRM, signalHandler); struct itimerval new_value, old_value; new_value.it_value.tv_sec = 1; new_value.it_value.tv_usec = 0; new_value.it_interval.tv_sec = 2; new_value.it_interval.tv_usec = 0; setitimer(ITIMER_REAL,

37、 &new_value, &old_value); for(;); return 0;43信号发送函数pause() 功能 使当前进程暂停,进入睡眠状态,直到被信号所中断,即将进程挂起等待信号到来。 函数原型 int pause(void); 返回值 -1 举例 使用alarm( )和pause( )实现sleep( )功能44信号发送函数pause()示例信号的安装(设置信号关联动作)信号的安装(设置信号关联动作) 如果进程要处理某一信号,那么就要在进程中安装该信号。安装信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信处理哪个信号号;该信号被

38、传递给进程时,将执行何种操作执行何种操作。 linux主要有两个函数实现信号的安装:signal()、sigaction()。其中signal()在非可靠信号系统调用的基础上实现, 是库函数。它只有两个参数两个参数,不支持信号传递信息,主要是用于前32种非实时信号的安装;而sigaction()是较新的函数(由两个系统调用实现:sys_signal以及sys_rt_sigaction),有三个参数有三个参数,支持信号传递信息,主要用来与 sigqueue() 系统调用配合使用,当然,sigaction()同样支持非实时信号的安装。sigaction()优于signal()主要体现在支持信号带有

39、参数。46信号安装函数signal() 原型定义 void (*signal(int signum, void (*handler)(int)(int); 参数说明 signum:需要安装的信号 handler:与安装信号相关的处理函数,可以是SIG_IGN或SIG_DFL SIG_IGN:忽略该信号 SIG_DFL:执行默认操作函数 返回值 成功时,返回新安装信号处理函数handler的值 失败时,返回SIG_ERR 底层系统调用 sys_signal(int sig, _sighandler_t handler)47信号安装函数signal()示例#include #include #in

40、clude #include void sig_usr(int sig);int main(int argc, char* argv) int i=0; if(signal(SIGUSR1, sig_usr) = SIG_ERR)printf(Cant catch SIGUSR1n); if(signal(SIGUSR2, sig_usr) = SIG_ERR) printf(“Cant catch SIGUSR2n”); while(1) printf(%2dn, i); pause(); i+; return 0;void sig_usr(int sig) if(sig = SIGUSR1

41、) printf(Received SIGUSR1n); else if(sig = SIGUSR2) printf(Received SIGUSR2n); else printf(Undeclared signal %d n,sig);执行: Gcc signal.c o signal ./signal&(以后台程序运行,并显示pid) Kill SIGUSR1 pid49信号安装函数sigaction()原型定义int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); siga

42、ction函数用于设定进程接收到特定信号后的行为。 第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。 第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,如果为空,进程会以缺省方式对信号处理; 第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。 第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过

43、程中应屏蔽掉哪些函数等等。底层系统调用 sys_sigaction(int sig, const struct old_sigaction _user *act, struct old_sigaction _user *oact) sigaction结构定义如下: sa_restorer,已过时,POSIX不支持它,不应再被使用。 联合数据结构中的两个元素_sa_handler以及*_sa_sigaction指定信号关联函数,即用户指定的信号处理函数。除了可以是用户自定义的处理函数外,还可以为SIG_DFL(采用缺省的处理方式),也可以为SIG_IGN(忽略信号)。 struct sigact

44、ion union _sighandler_t _sa_handler; void (*_sa_sigaction)( int, struct siginfo *, void *); _u sigset_t sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); 由_sa_handler 指定的处理函数只有一个参数,即信号值,所以信号不能传递除信号值之外的任何信息; 由_sa_sigaction 指定的信号处理函数带有三个参数,是为实时信号而设的(当然同样支持非实时信号),它指定一个3参数信号处理函数。第一个参数为信号值,第三个参

45、数没有使用(posix没有规范使用该参数的标准),第二个参数是指向siginfo_t 结构的指针,结构中包含信号携带的数据值,参数所指向的结构如下:siginfo_t int si_signo; /* 信号值,对所有信号有意义*/ int si_errno; /* errno值,对所有信号有意义*/ int si_code; /* 信号产生的原因,对所有信号有意义*/ pid_t si_pid; /* 发送信号的进程ID,对实时信号以及SIGCHLD有 意义 */ uid_t si_uid; /* 发送信号进程的真实用户ID,对kill(2),实时信号以及SIGCHLD有意义 */ int s

46、i_status; /* 退出状态,对SIGCHLD有意义*/ clock_t si_utime; /* 用户消耗的时间,对SIGCHLD有意义 */ clock_t si_stime; /* 内核消耗的时间,对SIGCHLD有意义 */ sigval_t si_value; /* 信号值,对所有实时有意义,是一个联合数据结构, /*可以为一个整数(由si_int标示,也可以为一个指针,由si_ptr标示)*/ void * si_addr; /* 触发fault的内存地址,对SIGILL,SIGFPE,SIGSEGV,SIGBUS 信号有意义*/ int si_band; /* 对SIGPO

47、LL信号有意义 */ int si_fd; /* 对SIGPOLL信号有意义 */ sa_mask:信号的集合。指定在信号处理程序执行过程中,哪些信号应当被阻塞。缺省情况下当前信号本身被阻塞,防止信号的嵌套发送。 注:sigaction()安装信号的处理函数执行过程中由sa_mask指定的信号才被阻塞。 sa_flags用于更改指定信号的行为。比较重要的标志位是SA_SIGINFO,当设定了该标志位时,表示信号附带的参数可以被传递到信号处理函数中,因此,应该为sigaction结构中的sa_sigaction指定处理函数,而不应该为sa_handler指定信号处理函数,否则,设置该标志变得毫无

48、意义。即使为sa_sigaction指定了信号处理函数,如果不设置SA_SIGINFO,信号处理函数同样不能得到信号传递过来的数据,在信号处理函数中对这些信息的访问都将导致段错误(Segmentation fault)。54信号安装函数sigaction()示例一#include #include #include #include void myFun(int sig);int main(int argc, char* argv) struct sigaction act, oldact; act.sa_handler = myFun; sigemptyset(&act.sa_mas

49、k); act.sa_flags = 0; sigaction(SIGUSR1, &act, &oldact); while(1) printf(Hello world!n); pause(); void myFun(int sig) printf(I got a signal:%dn,sig); Gcc sigacton1.c o sigaction ./sigaction& Kill SIGUSR1 pid信号安装函sigaction()数示例二#include #include #include #include void func(int signo, sigi

50、nfo_t *info, void *p) printf(signo = %dn, signo); printf(sender pid = %dn, info-si_pid);int main() struct sigaction act, oldact; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; act.sa_sigaction = func; sigaction(SIGUSR1, &act, &oldact); while(1) printf(pid is %d hello!n,getpid(); p

51、ause(); 在另外一个终端发送信号给当前进程sigqueue()函数调用示例在不同进程间传递整型参数.信号接收程序 #include #include #include #include #include void myFun(int, siginfo_t*, void* myfun); int main(int argc, char* argv) struct sigaction act; int sig; pid_t pid; pid = getpid(); printf(pid is%dn,pid); sigemptyset(&act.sa_mask); act.sa_sig

52、action = myFun; act.sa_flags = SA_SIGINFO;56 if(sigaction(SIGUSR1, &act, NULL)si_int); printf(Recv signum is%dn,signo); /raise(SIGKILL); sigqueue()函数调用示例在不同进程间传递整型参数.信号发送程序#include #include #include #include #include #include main(int argc, char* argv) pid_t pid; int signum; union sigval mysigva

53、l; pid = (pid_t)atoi(argv1); mysigval.sival_int = 8; if(sigqueue(pid, SIGUSR1, mysigval)=-1) printf(send errorn); sleep(2); return 0;57signal()与sigaction()的区别 不同点 signal() 安装的信号不能向信号处理函数传递信息 sigaction() 可设置进程的信号掩码,返回设置之前的sigaction结构 安装的信号可以向信号处理函数传递信息 相同点 都可以为指定的信号设置信号处理函数 共用同一个内核函数do_sigaction()585

54、9信号集操作函数信号集定义函数原型 int sigemptyset(sigset_t *set); 初始化信号集合set,将set设置为空 int sigfillset(sigset_t *set); 初始化信号集合,将信号集set设置为包含所有信号的集合 int sigaddset(sigset_t *set, int signo); 将信号signo加入到信号集set中 int sigdelset(sigset_t *set, int signo); 将信号signo从信号集set中删除 int sigismember(sigset_t *set, int signo); 查询信号sign

55、o是否在信号集set中 60信号操作函数sigprocmask( )功能 通过信号集set修改进程的信号阻塞集函数原型 int sigprocmask(int how, const sigset_t *set, sigset_t *oset);参数 how:函数操作方式 SIG_BLOCK:增加一个信号集到当前进程的阻塞集中 SIG_UNBLOCK:从当前阻塞集中删除一个信号集 SIG_SETMASK:将当前信号集设置为信号阻塞集合 set:当前进程的信号集 oset:保存当前进程的信号阻塞集说明 在使用之前需先设置好信号集合set61其他信号处理函数 sigpending(sigset_t

56、*set) 获取当前进程的未决信号集 set保存返回结果 sigsuspend(const sigset_t *mask) 在接收到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止 sigsuspend返回后将恢复调用之前的信号掩码 信号处理函数完成后,进程将继续执行 该系统调用始终返回-1,并将errno设置为EINTRtask_struct中与信号处理相关的成员 struct signal_struct *signal 信号描述符结构,为每种信号选择处理函数 struct sighand_struct *sighand 包含信号处理函数描述符的数组,信号作为

57、数组序号 sigset_t blocked, real_blocked; 被阻塞信号的掩码,每种信号类型对应一个元素 struct sigpending pending; 维护本进程中的未决信号 sigset_t saved_sigmask; 保存信号掩码 定义TIF_RESTORE_SIGMASK时恢复信号掩码62task_struct信号处理相关数据结构关系图6364System V IPC概述 IPC资源 表示单独的消息队列、共享内存或信号量集合 具有相同类型的接口函数 信号量集合 实现进程同步 消息队列以异步方式为通信频繁、但数据量少的进程通信提供服务 共享主存为数据量大的进程间通信提

58、供服务 共同点 通过 System V IPC对象通信时,需传递该对象的唯一IPC标识符 访问System V IPC对象时必须经过许可检验 System V IPC对象的访问权限由对象创建者设置65IPC对象标识符与IPC键 IPC标识符 由内核分配给IPC对象,在系统内部唯一 IPC对象标识符的获取:XXXget() 将IPC键传递给以sys_打头的内核函数,并为用户分配一个与IPC对象相对应的数据结构 返回一个32位IPC标识符,进程使用此标识符对该资源进行访问 IPC键 IPC对象的外部表示,可由程序员选择 如果键是公用的,则系统中所有进程通过权限检查后,均可找到和访问相应IPC对象

59、每个进程都可建立一个键值为IPC_PRIVATE的私有IPC对象66IPC键的创建 创建函数 key_t ftok( char * filename, int id); 功能说明 将一个现存文件名(对应文件必须是可访问的)和一个整数标识符id转换成一个key_t值 在Linux系统中,调用该函数时,系统将该文件的索引节点号取出,并在前面加上子序号,从而得到key_t返回值IPC资源的全局定义v消息队列 msgid_ds : 16个 定义位置:/proc/sys/kernel/msgmniv共享内存 shmid_ds : 4096个 定义位置:/proc/sys/kernel/shmmniv信号

60、量 semid_ds:128个 定义位置:/proc/sys/kernel/sem6768System V IPC的基本操作 操作函数(XXX代表msg、sem、shm三者之一) XXXget():获得IPC标识符 XXXctl():控制IPC资源 操作模式 先通过XXXget()创建一个IPC资源,返回IPC标识符 随后操作均以IPC资源标识符为参数,对相应IPC资源进行操作 其他进程可通过XXXget()获取已有的IPC资源标识符(权限允许的话),并对其操作请求IPC标识符时返回的错误码69错误码错误码说明说明EACCESS进程没有适当的访问权限进程没有适当的访问权限EEXIST进程试图创建一个和已有关键字相同的进程试图创建一个和已有关键字相同的IPC资源资源EINVAL在在XXXget(

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论