付费下载
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
信信号sil机制是ix系统中最为古老的进程之间的通信机制。ix信号也可以称为软中断,是在软件层次上对中断机制的一种模拟。在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号作是异步通知,通知接收信号的进程发生了什么。信号时间的发生有两个来硬件来源,比如我们按下了键盘或者其他硬件信号触kill软件来源,最常见发送信号的系统函 killLinux系统中定义了一系列的信号,可以
命令列出所有的信号Linux的信号机制是从Unix继承下来的,早期Unix系统只定义了32种信号,现在Linux支持64种信 6)SIGABRT:调用abort函数时产生该信号。默认动作为终止进程并产生core )) ) ))RMM)N():进程可以通过三种方式来响应和处理一个信忽略信号:即对信号不做任何处理,但是两个信号不能忽略捕捉信号:当信号发生时,执行用户定义的信号处理函
以 执行默认操作:Linux对每种信号都规定了默认操作,man7signal查看1123456789TermDefaultactionistoterminatetheIgnDefaultactionistoignoretheCoreDefaultactionistoterminatetheprocessanddumpcore(seecore(5)).StopDefaultactionistostoptheprocess.ContDefaultactionistocontinuetheprocessifitiscurrently行。#include#includevoid(*signal(intsig,void(*func)(int))主要用于前32种非实时信号的安:是要安装的信号值func:是指定信号处理函数,如果想忽略信号可以
(函数地址宏),如果想采用系统默认处理函 (函数地址宏) intsigaction(intsignum,conststructsigaction*act,structsigactionsigaction用于后32种实时信号的安装信号处SIGCHLD的产生条源代码#include#include#include#include5void{intpid_tpid=waitpid(‐1,&status,WUNTRACED|printf("recvchildpid%d\n",printf("childprocessexitedwith%d\n",elseprintf("childprocesssignaledwith%d\n",elseprintf("childprocesselseprintf("childprocess intmain(intargc,char** pid_tsignal(SIGCHLD,pid=if(pid=={printf("childPID[%d]\n", elseif(pid!={{ { 运行结果where@ubuntu:~where@ubuntu:~$childPIDchildPID[9881]return并不是每个进程都可以向其他的进程发送信号。一般的进程只能向具有相同i和i同进程组中的其他进程发送信号。常用的发送信号的函数有kill、is、lm、stitim、t等。kill()函数可以给指定的进程发送某一个信号,其函数原型是#include#includeintkill(pid_tpid,int参 含义pid含pid>给PID为pid的进程发送信pid=给同一个进程的所有进程发送pid<0pid!=-给进程组ID为pid的所有进程发送信pid=-给除了自身之外的PID大于1的进程发送 通过errno以及perror可以查看错误宏含所发送的信号无效没有向目标进程发送信号的权目标进程不存在或进程已经终止,处于僵尸状源代码1123456789#include#includevoid{}intmain(intargc,char**{pid_tpid;if(pid==0){printf("childprocess\n");kill(getppid(),SIGBUS);}elseif(pid!={{}}{}return}raise()函数用户给进程本身发送一个信号,其函数原型#include#includeintraise(int源代#include#include#include#includevoidhandle_sig(int{if(sig=={printf("get intmain(intargc,char**{signal(SIGBUS,return 定时器函数,alarm()专为SIGALRM信号设计,其函数原型#include#includeunsignedintalarm(unsignedint参 是定时器的时间,单位为秒,当设置了alarm()之后,在指定
秒之后,将给自己发一个SIGALRM信号,当参 为0的时候,将清除当前进程的alrm设置调用lm函数时,如果进程已经有一个未结束的lm,那么旧的lm将被删除,并返回旧的lm的剩余时间。否则lm函数返回。源代码:1123456789#include#include<unistd.h>#include<signal.h>voidhandle_sig(intsig){staticinti=printf("signalalarm%d\n",i++);}intmain(intargc,char**{signal(SIGALRM,{}return}更强大的定时器函数setitimer(),其函数原型如下 intsetitimer(intwhich,conststructitimerval*value,structitimerval*which参数指定定时器类含以系统真实的时间来计算,它送出SIGALRM信号以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号value参数指定定时时间1123456789structitimervalstructtimevalit_interval;/*每隔多少秒发送一次信号structtimeval/*第一次定时时间structtimevalsuseconds_t/*seconds/*microseconds123456789#include#include<signal.h>#include<unistd.h>voidhandle_sig(123456789#include#include<signal.h>#include<unistd.h>voidhandle_sig(intsig){staticinti=printf("signalalarm[%d]\n",}intmain(intargc,char**{structitimervaltimval;timval.it_interval.tv_usec=timval.it_value.tv_usec=0;signal(SIGALRM,handle_sig);{}return abort()向进程发送SIGABORT信号,默认情况下进程会异常退管道符:一个用与而另一个用于写入。任何从管道写入端写入的数据,可以从管道端读出。管道通信具有以下特点管道存放在内存中,是一种独立的文件系系统调用pipe()用于创建一个管道,其函数原型如#include#includeintpipe(int
文件描述符用来从管道 如果管道读端被关闭,那么这个时候如果
管道,会发出信
。如果管道写端被关闭那么这个时候如果继
管道直接返回0源代#include#include3voidchild_process(int{inti=charwritebuf[128]=8{sprintf(writebuf,"writepipe:%d",i); write(pipefd[1],writebuf, printf("writepipe:%s\n", i=(i+1)% voidfather_process(int{charreadbuf[128]={ printf("readpipe:%s\n", intmain(intargc,char**{intpid_tif(pipe(pipefd)=={return pid=if(pid=={ elseif(pid!={}{}return}运行结果:子进程写数据,父进程读出数据并且打where@ubuntu:~where@ubuntu:~$writepipe:writepipe:readpipe:writepipe:writepipe:writepipe:readpipe:writepipe:writepipe:writepipe:readpipe:writepipe:writepipe:writepipe:命名管道FIFO是firstinfirstout(先进先出)的缩写,FIFO也称为“命名管道”。FIFO是一种特殊类型的管道,它在文件
函数创建。在FIFO文件创建之后,任何一个具有适当权限的进程都可以mkfifo()函数原型为#include#includeintmkfifo(constchar*pathname,mode_t参数一个FIFO文件的路径名与普通文
函数中的mode参数相同返回值如果要创建的文件已经存在,返回- 错误,成功返回0#include#include#include#include#includevoidhandle_sig(int{printf("signal intmain(intargc,char**{intintcharinti=signal(SIGPIPE,if(mkfifo("./fifo",0640)=={if(errno!={return fd=open("./fifo",if(fd=={return sprintf(buf,"data%d", ret=write(fd,buf,strlen(buf)); printf("writefifo[%d]%s\n",ret,buf); return 源码中,通过mkfifo来创建FIFO文件,并且以只写的方式打开,只有当两边的管道都打开的时候才能..
函数上,如果管道另一端打开后被关闭,那么这个时候如果继
FIFO管道,源代码1123456789#include#include<unistd.h>#include<stdio.h>#include<errno.h>#includeintmain(intargc,char**{intfd;charbuf[128];if(mkfifo("./fifo",0640)==‐1){if(errno!=EEXIST)/*如果错误类型是fifo文件已经存在,则继续执行{return‐1;}}fd=open("./fifo",O_RDONLY);if(fd==‐1){return‐1;}{memset(buf,0,ret=read(fd,buf,sizeof(buf)‐1);printf("readfifo[%s]:%s\n",ret,buf);}return}
使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志如果所有指向管道写端的文件描述符都关闭了(管道写端的计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被后,再次read会返回0,就像读到文件末尾一样。如果有指向管道写端的文件描述符没关闭(管道写端的计数大于),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被后,再次会阻塞,直到管道中有数据可读了才数据并返回。如果所有指向管道读端的文件描述符都关闭了(管道读端的计数等于),这时有进程向管道的写端it,那么该进程会收到信号SIPIPE,通常会导致进程异常终止。讲信号时会讲到怎样使SIPIPE信号不终止进程。如果有指向管道读端的文件描述符没关闭(管道读端的计数大于),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次it会阻塞,直到管道中有空位置了才写入数据并返回。信号在Unix的SystemV版本,AT&T引进了一种新形式的IPC机制(Inter-ProcessCommunication,进程间通信),SystemIPC中,对于每一个新建的信号量、消息队列以及共享内存,都有一个在整个系统中唯一的标识符,在终端输入命 ,可以看到目前系统中所有的IPC信息1where@ubuntu:~$234 拥有 权 字5 26 27 28 29 2 2 2 2 2信号量数组 拥有者权 消息队列 拥有者权 已用字节数消#include#includekey_tftok(constchar*pathname,int#include#includekey_tftok(constchar*pathname,intkey_t函数返key_t字
指向的文件相对应文件索引节
来确定一个IPC关必须是一个已经存在并具 权限的文件
只有最低的8个字节是有效的,所以通常用ASCII字符来作 。
完全相同时,每次调
都会获取一个相同的键通过调用semget()创建信号量集,其函数原型是#include#include#include#includeintsemget(key_tkey,intnsems,int :是信号量键值。 :是信号量的数目参 :是一些标志。这些标志包括:如果key指定的信号量不存在,创建一个新信号量集: 标志一起使用,如果信号量已经存在,返回错误返回值
调用成功时,返回与键 对应的信号量集的标识符,否则返回-1当进程需要申请或者释放公共资源时候,可以调用semop()来对信号量进行操作,其函数原型#include#include#include#includeintsemop(intsemid,structsembuf*sops,unsigned参 是信号量ID参 指向一
结构的数组,每一
结构都定义了在对信号量的操参 为sops指向数组的大小其 结构如下112345structunsignedshort;对应信号集中的信号量的索引是一个指定了操作类型的整数,如果sem_op是一个正整数,则这个值会立刻被加到信号量的值上。 量的值至少等于操作值的绝对值。
为0,这个操作会导致进程阻塞,直到信号量的值为零才恢
非阻塞操作,如
,Linux会在进程退出的时返回值
调用成功时返回0,否则返回-的功能和semop()基本一样,只是增加了一个时间限制,其函数原型如 intsemtimedop(intsemid,structsembuf*sops,unsignednsops,structtimespec*如果信号量操作时进程被阻塞,那么经过timeout时间后,还是没有可用资源,那么函数会立即返系统调用用于对信号量的各种控制操作,其函数原型#include#include#include#includeintsemctl(intsemid,intsemnum,intcmd,参 指定信号量集参 指定了对信号量集里面的哪一个信号量进行操作参 指定具体的操作类型操一个信号量集的数据结构semid_ds,并将其在semun中的buf参数中设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf从内存中立即删除信号量用于信号量集中的所有信号量的值T返回正在等待资源的进程返回最后一个对信号量操作的进程返回信号量集中的一个单个的信号量的T返回等待semnum锁代表的信号量值成为0的进程数目设置信号量集中的所有的信号量的设置semnum所代表信号量的值最后一个是可选参数,取决 的值,必须是这样一个1123456789unionsemunval;/*Valueforsemid_ds*buf;/*Bufferforunsigned *arrary;/*Bufferfor/*structsemid_ds在sys/sem.h中定义structsemid_dsstructipc_permsem_perm;/*Ownershipandpermissionssem_otime;/*Lastsemoptimesem_ctime;/*Lastchangetime*/sem_nsems;/*No.ofsemaphoresinset*/调用失败时返回-1,调用成功时,根据cmd的不同,返回值也各不相同,具体可以查看semctlman手册
并不初始化各个信号量的值,这个初始化必须通,查询当前等待在某个信号量上的进程
命令或
命令调 printf("%dprocesseswaitforsemid[%d]",semctl(semid, 使 ,删除信号量集 semctl(semid,0,#include#include#include#include8unionsemunintstructsemid_dsunsignedshort intmain(intargc,char{intintkey_tkey=ftok("./creat",if(key=={return semidsemget(key1IPC_CREAT|IPC_EXCL|0666);//创建1个信号if(semid=={if(errno=={semid=semget(key,1,printf("semid[%d]alreadyexist\n", {return {unionsemunsem_args.setval= rsret=semctl(semid,0,SETVAL,if(ret=={return }}structsembufsem_opt_request[1]={0,‐1,SEM_UNDO};structsembufsem_opt_release[1]={0,1,SEM_UNDO};{printf("PID[%d]wait...\n",semop(semid,sem_opt_request,1);//获取进程2的资源,让进程2等待printf("PID[%d]requested\n",getpid());semop(semid,sem_opt_release,1);//唤醒进程1,即释放资源的使用权printf("PID[%d]release\n",getpid());}return从队列中,每一个消息队列用一个唯一的IP标识符表示。系统定义的消息类型#include#includestructlongchar 指消息的类型,它由一个整数来代表,并且它只能是大于0的整数是消息本身字段不但可以字符,还可以任何其他的数据类型,此字段可以说是完全任意的,因为程序员structstructlongcharstructclient 这里的消息类型字段和前面的一样,但数据结构的其余部分则由其他的两个成员所代替,而其中 还是个结构体,这就体现了消息队列的灵活之处。内核本身并不对消息结构中的数据做任何翻译。你可以再其中发送任何消息,但存在一个内部给定的消息大小的限制。在ix系统中,消息的最大的长度是个字节,其中包括mty,它占用个字节的长度。系统调用msgget()用于创建一个新的消息队列,或者存取一个已经存在的消息队列,其函数原型#include#include#includeintmsgget(key_tkey,int 参 是消息队列关键字值,可以通 获得参 是一些标志IPC_CREATIPC_CREAT: 执行成功时,返回消息队列的标识符,否则返回-1,通
查看错误信下面是一个打开和创建消息队列的例子,函数返回消息队列的标识intintopen_queue(key_t{intqid=msgget(keyval,IPC_CREAT|if(qid=={return return
系统调用用于向队列发 intmsgsnd(intmsqid,structmsgbuf*msgp,sizetmsgsz,int 参 :是队列标识符参 :是指向消息缓冲区的指针参 :指定了消息的字节大小,但是不包括消息类型的长度(4个字节)参 :可以设置为值含0此时为忽略此参数,如果队列已满,调用进程将会挂起,直到消息可以写入到队列消息源码intintsend_message(intqid,structmymsgbuf*{intlength=sizeof(structmymsgbuf)‐result=msgsnd(qid,qbuf,length,if(result=={return return msgrcv()系统调用用于从消息队列一条消息,其函数原型是 ssize_tmsgrcv(intmsqid,structmsgbuf*msgp,size_tmsgsz,longmsgtype,int 参 :消息队列的标识符参 :代表要消息的缓冲区的地址参数msgsz:消息缓冲区的长度,不包括mtype的长度,它可以按照如下方法计算mysmsgbufsizeof(long参 :是要从消息队列 的消息的类型。如 ,接收到消息队列的第一个消息。
绝对值的所参 取值为值含0此时为忽略此参数,如果队列已满,调用进程将会挂起,直到消息可以写入到队列下面时一个接收消息的例intintread_message(intqid,longtype,structmymsgbuf{intresult,length=sizeof(structmymsgbuf)‐result=msgrcv(qid,qbuf,length,type,if(result=={return return #includestruct{longchar 9intsend_message(intqid,structmymsgbuf*{intlength=sizeof(structmymsgbuf)‐result=msgsnd(qid,qbuf,length,if(result=={return return intmain(intargc,char**{structmymsgbufkey_tkeyval=ftok("./creat",inti=if(keyval=={return intqid=msgget(keyval,IPC_CREAT|if(qid=={return {msg.mtype=sprintf(msg.buf,"msg%d",send_message(qid,printf("sendmessage:mtype[%ld]buf[%s]\n",msg.mtype, return 源码#includestruct{longchar 9 intread_message(intqid,longtype,structmymsgbuf*{intlength=sizeof(structmymsgbuf)‐result=msgrcv(qid,qbuf,length,type,if(result=={return return intmain(intargc,char**{structmymsgbufkey_tkeyval=ftok("./creat",inti=if(keyval=={return intqid=msgget(keyval,IPC_CREAT|if(qid=={return {read_message(qid,100,printf("readmessage:mtype[%ld]buf[%s]\n",msg.mtype, return 消息队列标识符的属性被记录在一个msgid_ds结构体1123456789structstructipc_permmsg_perm;/*所有者和权限msg_stime;/*最后一次向队列发送消息的时间msg_rtime/*最后一次从队列接收消息的时间*/msg_ctime;/*队列最后一次改动的时间*/msg_cbyptes;/*当前队列所有消息的总长度}通过msgctl()可以对消息队列进行控制或者一些属性的修改,其函数原型 intmsgctl(intmsgid,intcmd,structmsqid_ds*参 :是消息队列的标识符参 :指定了操作含消息队列的数据结构msqid_ds,并将其在buf指定的地址中设置消息队列的数据结构msqid_ds中的ipc_permmsg_qbytesmsg_ctime元素的值。这从系统内核中移走消息队下面是一个删除消息队列的例intintremove_queue(int{if(msgctl(qid,IPC_RMID,0)=={return return 共享内存可以说是最有用的进程间通信方式,也是最块的IPC形式。两个不同进程A、B共享内存的基本原是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存种数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。系统调用shmget()用于创建共享内存或者获取一个已经存在的共享内存的标识符,其函数原型#include#include#includeintshmget(key_tkey,size_tsize,int 参 是一些标志,包括含如果内核中没有此共享内存,则创建当和IPC_CREAT一起使用时,如果共享内存已经存在,则返回错返回:当shmget()执行成功时,返回共享内存的标识符,否则返回-1,通
查看错误值获取共享内存标识intintopen_segment(key_tkeyval,int{intshmid=shmget(keyval,segsize,IPC_CREAT|if((shmid=={return return 系统调用shmat()可以获取一个共享内存的地址,并将其连接到进程中,其函数原型 void*shmat(intshmid,constvoid*shnaddr,int 参 :是共享内存标识符参 与参 关联使用用含shmaddr为共享内
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 医学26年:肾上腺疾病护理要点 查房课件
- 2026年智能制造数据分析报告
- 2025年智慧政务APP服务创新趋势报告
- 肿瘤患者基因检测依从性影响因素
- 氡检测技术在室内环境监测中的量子点传感阵列应用
- 第四节 离子晶体说课稿2025学年高中化学人教版选修3物质结构与性质-人教版2004
- 高中2025情绪认知活动主题班会说课稿
- 2025年NDC 3.0工业脱碳指南报告(英文版)-
- 2026年is阅读测试题及答案
- 2026年麦当劳基础测试题及答案
- 2026年租赁烘干塔合同(1篇)
- 2026年金属非金属矿山(露天矿山)安全管理人员试题附答案详解【考试直接用】
- 2026年高校学报编辑部期刊出版岗应聘笔试指南及规范
- 2025年csco肾癌诊疗指南
- 2026年中级银行从业资格《个人理财》通关测试卷及一套完整答案详解
- 2025年湖北省工程专业中级职务水平能力测试(林业)综合试题及答案
- 广告制作安装工作制度
- 东莞广告行业分析报告
- 中国艺术研究院社会招聘试题
- 2026重庆忠县规划和自然资源局招聘临时聘用人员1人考试参考试题及答案解析
- 【《基于UASB-MBR工艺的垃圾渗滤液处理系统工艺计算设计案例》7400字】
评论
0/150
提交评论