UNIX多进程编程.pdf
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《UNIX多进程编程.pdf》由会员分享,可在线阅读,更多相关《UNIX多进程编程.pdf(22页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、UNIX多进程编程UNIX多进程编程写在前面的话 本文主要根据本人在UNIX系统上的编程实践经验总结而成,既做为自己在一个时期内编程实践的部分总结,又可成为文章发表.对UNIX程序员初学者来说是一个小小的经验,仅供参考;对UNIX老手来说则不值一哂,请各位多多指教.一.多进程程序的特点 由于UNIX系统是分时多用户系统,CPU按时间片分配给各个用户使用,而在实质上应该说CPU按时间片分配给各个进程使用,每个进程都有自己的运行环境以使得在CPU做进程切换时不会忘记该进程已计算了一半的半成品.以DOS的概念来说,进程的切换都是一次DOS中断处理过程,包括三个层次:(1)用户数据的保存:包括正文段(
2、TEXT),数据段(DATA,BSS),栈段(STACK),共享内存段(SHARED MEMORY)的保存.(2)寄存器数据的保存:包括PC(program counter,指向下一条要执行的指 令的地址),PSW(processor status word,处理机状态字),SP(stack pointer,栈指针),PCBP(pointer of process control block,进程控制块指针),FP(frame pointer,指向栈中一个函数的local变量的首地址),AP(augument pointer,指向栈中函数调用的实参位置),ISP(interrupt stack
3、 pointer,中断栈指针),以及其他的通用寄存器等.(3)系统层次的保存:包括proc,u,虚拟存储空间管理表格,中断处理栈.以便于该进程再一次得到CPU时间片时能正常运行下去.既然系统已经处理好所有这些中断处理的过程,我们做程序还有什么要担心的呢?我们尽可以使用系统提供的多进程的特点,让几个程序精诚合作,简单而又高效地把结果给它搞出来.另外,UNIX系统本身也是用C语言写的多进程程序,多进程编程是UNIX的特点,当我们熟悉了多进程编程后,将会对UNIX系统机制有一个较深的认识.首先我介绍一下多进程程序的一些突出的特点:1.并行化 一件复杂的事件是可以分解成若干个简单事件来解决的,这在程序
4、员的大脑中早就形成了这种概念,首先将问题分解成一个个小问题,将小问题再细分,最后在一个合适的规模上做成一个函数.在软件工程中也是这么说的.如果我们以图的方式来思考,一些小问题的计算是可以互不干扰的,可以同时处理,而在关键点则需要统一在一个地方来处理,这样程序的运行就是并行的,至少从人的时间观念上来说是这样的.而每个小问题的计算又是较简单的.2.简单有序 这样的程序对程序员来说不亚于管理一班人,程序员为每个进程设计好相应的功能,并通过一定的通讯机制将它们有机地结合在一起,对每个进程的设计是简单的,只在总控部分小心应付(其实也是蛮简单的),就可完成整个程序的施工.3.互不干扰 这个特点是操作系统的
5、特点,各个进程是独立的,不会串位.4.事务化 比如在一个数据电话查询系统中,将程序设计成一个进程只处理一次查询即可,即完成一个事务.当电话查询开始时,产生这样一个进程对付这次查询;另一个电话进来时,主控程序又产生一个这样的进程对付,每个进程完成查询任务后消失.这样的编程多简单,只要做一次查询的程序就可以了.二.常用的多进程编程的系统调用 1.fork()功能:创建一个新的进程.语法:#include#include pid_t fork();说明:本系统调用产生一个新的进程,叫子进程,是调用进程的一个复制品.调用进程叫父进程,子进程继承了父进程的几乎所有的属性:.实际UID,GID和有效UID
6、,GID.1.环境变量.附加GID.调用exec()时的关闭标志.UID设置模式比特位.GID设置模式比特位.进程组号.会话ID.控制终端.当前工作目录.根目录.文件创建掩码UMASK.文件长度限制ULIMIT.预定值,如优先级和任何其他的进程预定参数,根据种类不同决定是否可以继承.还有一些其它属性.但子进程也有与父进程不同的属性:.进程号,子进程号不同与任何一个活动的进程组号.父进程号.子进程继承父进程的文件描述符或流时,具有自己的一个拷贝并且与父进程和其它子进程共享该资源.子进程的用户时间和系统时间被初始化为0.子进程的超时时钟设置为0.子进程的信号处理函数指针组置为空.子进程不继承父进程
7、的记录锁.返回值:调用成功则对子进程返回0,对父进程返回子进程号,这也是最方便的区分父子进程的方法.若调用失败则返回-1给父进程,子进程不生成.例子:pid_t pid;if(pid=fork()0)else if(pid=0)exit(0);/*注意子进程必须用exit()退出运行*/else printf(fork errorn);exit(0);2.system()功能:产生一个新的进程,子进程执行指定的命令.语法:#include#include int system(string)char*string;说明:本调用将参数string传递给一个命令解释器(一般为sh)执行,即stri
8、ng被解释为一条命令,由sh执行该命令.若参数string为一个空指针则为检查命令解释器是否存在.该命令可以同命令行命令相同形式,但由于命令做为一个参数放在系统调用中,应注意编译时对特殊意义字符的处理.命令的查找是按PATH环境变量的定义的.命令所生成的后果一般不会对父进程造成影响.返回值:当参数为空指针时,只有当命令解释器有效时返回值为非零.若参数不为空指针,返回值为该命令的返回状态(同waitpid()的返回值.命令无效或语法错误则返回非零值,所执行的命令被终止.其他情况则返回-1.例子:char command81;2int i;for(i=1;i8;i+)sprintf(command
9、,ps-t tty%02i,i);system(command);3.exec()功能:执行一个文件 语法:#include int execl(path,arg0,.,argn,(char*)0)char*path,*arg0,.,*argn;int execv(path,argv)char*path,*argv;int execle(path,arg0,.,argn,(char*)0,envp)char*path,*arg0,.,*argn,*envp;int execve(path,argv,envp)char*path,*argv,*envp;int execvp(file,argv)
10、char*file,*argv;说明:这是一个系统调用族,用于将一个新的程序调入本进程所占的内存,并覆盖之,产生新的内存进程映象.新的程序可以是可执行文件或SHELL批命令.当C程序被执行时,是如下调用的:main(int argc,char*argv,char*envp);argc是参数个数,是各个参数字符串指针数组,envp是新进程的环境变量字符串的指针数组.argc至少为1,argv0为程序文件名,所以,在上面的exec系统调用族中,path为新进程文件的路径名,file为新进程文件名,若file不是全路径名,系统调用会按PATH环境变量自动找对应的可执行文件运行.若新进程文件不是一个可
11、执行的目标文件(如批处理文件),则execlp()和execvp()会将该文件内容作为一个命令解释器的标准输入形成system().arg0,.等指针指向0结束的字符串,组成新进程的有效参数,且该参数列表以一个空指针结束.反过来,arg0至少必须存在并指向新进程文件名或路径名.同样,argv是字符串指针数组,argv0指向新进程文件名或路径名,并以一空指针结束.envp是一个字符串指针数组,以空指针结束,这些字符串组成新进程的环境.在调用这些系统调用前打开的文件指针对新进程来说也是打开的,除非它已定义了close-on-exec标志.打开的文件指针在新进程中保持不变,所有相关的文件锁也被保留.
12、调用进程设置并正被捕俘的信号在新进程中被恢复为缺省设置,其它的则保持不变.新进程启动时按文件的SUID和SGID设置定义文件的UID和GID为有效UID和GID.新进程还继承了如下属性:.附加GID.进程号.父进程号.进程组号.会话号.控制终端.alarm时钟信号剩下的时间.当前工作目录.根目录.3.文件创建掩码.资源限制.用户时间,系统时间,子进程用户时间,子进程系统时间.记录锁.进程信号掩码.信号屏蔽.优先级.预定值.调用成功后,系统调用修改新进程文件的最新访问时间.返回值:该系统调用一般不会有成功返回值,因为原来的进程已荡然无存.例子:printf(now this process wi
13、ll be ps commandn);execl(/bin/ps,ps,-ef,NULL);4.popen()功能:初始化从/到一个进程的管道.语法:#include FILE*popen(command,type)char*command,type;说明:本系统调用在调用进程和被执行命令间创建一个管道.参数command做为被执行的命令行.type做为I/O模式,r为从被执行命令读,w为向被执行命令写.返回一个标准流指针,做为管道描述符,向被执行命令读或写数据(做为被执行命令的STDIN或STDOUT)该系统调用可以用来在程序中调用系统命令,并取得命令的输出信息或者向命令输入信息.返回值:不
14、成功则返回NULL,成功则返回管道的文件指针.5.pclose()功能:关闭到一个进程的管道.语法:#include int pclose(strm)FILE*strm;说明:本系统调用用于关闭由popen()打开的管道,并会等待由popen()激活的命令执行结束后,关闭管道后读取命令返回码.返回值:若关闭的文件描述符不是由popen()打开的,则返回-1.例子:printf(now this process will call popen system calln);FILE*fd;if(fd=popen(ps-ef,r)=NULL)printf(call popen failedn);re
15、turn;else char str80;while(fgets(str,80,fd)!=NULL)printf(%sn,str);pclose(fd);6.wait()功能:等待一个子进程返回并修改状态 语法:#include#include pid_t wait(stat_loc)int*stat_loc;4说明:允许调用进程取得子进程的状态信息.调用进程将会挂起直到其一个子进程终止.返回值:等待到一个子进程返回时,返回值为该子进程号,否则返回值为-1.同时stat_loc返回子进程的返回值.例子:/*父进程*/if(fork()0)wait(int*)0);else exit(0);7.
16、waitpid()功能:等待指定进程号的子进程的返回并修改状态 语法:#include#include pid_t waitpid(pid,stat_loc,options)pid_t pid;int*stat_loc,options;说明:当pid等于-1,options等于0时,该系统调用等同于wait().否则该系统调用的行为由参数pid和options决定.pid指定了一组父进程要求知道其状态的子进程:-1:要求知道任何一个子进程的返回状态.0:要求知道进程号为pid值的子进程的状态.0)waitpid(pid,&stat_loc,0);else exit(1);printf(stat
17、_loc is%dn,stat_loc);8.setpgrp()功能:设置进程组号和会话号.语法:#include pid_t setpgrp()说明:若调用进程不是会话首进程.将进程组号和会话号都设置为与它的进程号相等.并释放调用进程的控制5终端.返回值:调用成功后,返回新的进程组号.例子:/*父进程处理*/if(fork()0)else setpgrp();exit(0);9.exit()功能:终止进程.语法:#include void exit(status)int status;说明:调用进程被该系统调用终止.引起附加的处理在进程被终止前全部结束.返回值:无 10.signal()功能
18、:信号管理功能 语法:#include void(*signal(sig,disp)(int)int sig;void(*disp)(int);void(*sigset(sig,disp)(int)int sig;void(*disp)(int);int sighold(sig)int sig;int sigrelse(sig)int sig;int sigignore(sig)int sig;int sigpause(sig)int sig;说明:这些系统调用提供了应用程序对指定信号的简单的信号处理.signal()和sigset()用于修改信号定位.参数sig指定信号(除了SIGKILL和
19、SIGSTOP,这两种信号由系统处理,用户程序不能捕捉到).disp指定新的信号定位,即新的信号处理函数指针.可以为SIG_IGN,SIG_DFL或信号句柄地址.若使用signal(),disp是信号句柄地址,sig不能为SIGILL,SIGTRAP或SIGPWR,收到该信号时,系统首先将重置sig的信号句柄为SIG_DFL,然后执行信号句柄.若使用sigset(),disp是信号句柄地址,该信号时,系统首先将该信号加入调用进程的信号掩码中,然后执行信号句柄.当信号句柄运行结束后,系统将恢复调用进程的信号掩码为信号收到前的状态.另外,使用sigset()时,disp为SIG_HOLD,则该信号
20、将会加入调用进程的信号掩码中而信号的定位不变.sighold()将信号加入调用进程的信号掩码中.6sigrelse()将信号从调用进程的信号掩码中删除.sigignore()将信号的定位设置为SIG_IGN.sigpause()将信号从调用进程的信号掩码中删除,同时挂起调用进程直到收到信号.若信号SIGCHLD的信号定位为SIG_IGN,则调用进程的子进程在终止时不会变成僵死进程.调用进程也不用等待子进程返回并做相应处理.返回值:调用成功则signal()返回最近调用signal()设置的disp的值.否则返回SIG_ERR.例子一:设置用户自己的信号中断处理函数,以SIGINT信号为例:in
21、t flag=0;void myself()flag=1;printf(get signal SIGINTn);*下步骤*/void(*a)();a=myself;signal(SIGINT,a);flag=2;main()while(1)sleep(2000);/*等待中断信号*/if(flag=1)printf(skip system call sleepn);exit(0);if(flag=2)printf(skip system call sleepn);printf(waiting for next signaln);11.kill()功能:向一个或一组进程发送一个信号.语法:#in
22、clude#include int kill(pid,sig);pid_t pid;int sig;说明:本系统调用向一个或一组进程发送一个信号,该信号由参数sig指定,为系统给出的信号表中的一个.若为0(空信号)则检查错误但实际上并没有发送信号,用于检查pid的有效性.pid指定将要被发送信号的进程或进程组.pid若大于0,则信号将被发送到进程号等于pid的进程;若pid等于0则信号将被发送到所有的与发送信号进程同在一个进程组的进程(系统的特殊进程除外);若pid小于-1,则信号将被发送到所有进程组号与pid绝对值相同的进程;若pid等于-1,则信号将被发送到所有的进程(特殊系统进程除外).
23、信号要发送到指定的进程,首先调用进程必须有对该进程发送信号的权限.若调用进程有合适的优先级则具备有权限.若调用进程的实际或有效的UID等于接收信号的进程的实际UID或用setuid()系统调用设置的UID,或sig等于SIGCONT同时收发双方进程的会话号相同,则调用进程也有发送信号的权限.7若进程有发送信号到pid指定的任何一个进程的权限则调用成功,否则调用失败,没有信号发出.返回值:调用成功则返回0,否则返回-1.例子:假设前一个例子进程号为324,现向它发一个SIGINT信号,让它做信号处理:kill(pid_t)324,SIGINT);12.alarm()功能:设置一个进程的超时时钟.
24、语法:#include unsigned int alarm(sec)unsigned int sec;说明:指示调用进程的超时时钟在指定的时间后向调用进程发送一个SIGALRM信号.设置超时时钟时时间值不会被放入堆栈中,后一次设置会把前一次(还未到超时时间)冲掉.若sec为0,则取消任何以前设置的超时时钟.fork()会将新进程的超时时钟初始化为0.而当一个进程用exec()族系统调用新的执行文件时,调用前设置的超时时钟在调用后仍有效.返回值:返回上次设置超时时钟后到调用时还剩余的时间秒数.例子:int flag=0;void myself()flag=1;printf(get signal
25、 SIGALRMn);*以下步骤*/void(*a)();a=myself;signal(SIGALRM,a);flag=2;main()alarm(100);/*100秒后发超时中断信号*/while(1)sleep(2000);/*等待中断信号*/if(flag=1)printf(skip system call sleepn);exit(0);if(flag=2)printf(skip system call sleepn);printf(waiting for next signaln);13.msgsnd()功能:发送消息到指定的消息队列中.语法:#include#include#i
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- UNIX 进程 编程
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内