c语言多进程多线程编程(6)

2019-08-02 01:35

if ((int)area1==-1) {

printf(\ exit(1); }

/*取得共享数据段area1的版本号*/

v=sdgetv(area1);

/*申请访问共享数据段area1,若已有进程在访问该段则本进程挂 *起,否则进入访问并将该数据段加写锁*/ sdenter(area1,SD_WRITE);

/*对共享数据段访问,写10个a*/

strcpy(area1,\

/*申请解除访问权限,若已有进程申请访问则激活该进程*/ sdleave(area1); /*进程处理过程*/

/*等待取共享数据段area1的版本号*/ sdwaitv(area1,v);

/*重新申请访问共享数据段area1*/ sdenter(area1,SD_WRITE); /*读取共享数据段中的数据*/

memcpy(buf,area1,20);

/*申请解除访问权限,若已有进程申请访问则激活该进程*/ sdleave(area1);

printf(\

2.31.getenv() 取得指定环境变量值

功能:取得指定环境变量值. 语法:

#include #include char *getenv(name) char *name;

说明:本系统调用检查环境字符串(格式如name=\并在找到有指\定名字的环境值后,返回指向value字符串的指针.否则返回空指 针. 返回值:如前述. 例子:

char * value;

value=getenv(\

printf(\将打印出HOME环境变量的值*/

2.32.putenv() 修改或增加环境值

功能:修改或增加环境值.

语法:

#include int putenv(string) char *string;

说明:参数string指向一个字符串,格式如下:

name=value

本系统调用将环境变量name等于值value,修改或增加一个环境变 量,字符串string成为环境的一部分.

返回值:若putenv()不能取得合适的内存空间则返回非0值,否则返回0. 例子:/*父进程处理*/

putenv(\ putenv(\TH=/bin\ if (fork()>0)

exit(0); /*父进程退出运行*/ /*子进程处理*/

setpgrp();

/*父进程设置的环境变量已传到子进程*/ char * value1;

value1=getenv(\ value2=getenv(\TH\

printf(\TH=[%s]\\n\ /*将打印出\和\TH=/bin\

三.多进程编程技巧

3.1.主要程序结构 3.1.1事件主控方式

若是应用程序属于事务处理方式,则在主函数中设计为监控事件发生, 当事件发生时,可以生成一个新的进程来处理该事务,事务处理完成后就 可以让子进程退出系统.这种处理方式一般不要消息传递.

3.1.2信息协调方式

若是应用程序需要由多个进程协调处理完成,则可以生成这些进程, 通过消息在进程间的传递,使各个进程能相互协调,共同完成事务.这种处理方式一般是用fork()生成几个进程后,用exec()调用其它程序文件,使得不同的程序同时在系统内运行.然后通过IPC机制传送消息,使各个程序能协调运行.

3.2.选择主体分叉点 3.2.1事件初始产生

对应于事件主控方式的程序结构.关键点在于以何种方式选择事件的初始发生点,如网络程序给出的建链信息.主控程序在收到该消息后就认为是一个事件开始,则可以产生一个子进程处理后面的事务:接收交易信息,事务处理,发送返回交易信息,关闭链接等,完成后将子进程退出系统.

3.2.2主程序自主产生

对应于信息协调方式的程序结构.主控程序只负责生成几个子进程,各个子进程分别调用exec()将不同的执行文件调入内存运行,主控程序在生成所有的子进程后即可退出系统,将子进程留在内存中运行.

3.3.进程间关系处理 3.3.1父子进程关系

. 进程组处理

进程组的概念是这样的,当系统启动时,第一个进程是init,其进程 组号等于进程号,由它产生的所有子进程的进程组号也相同,子进程 的子进程也继承该进程组号,这样,由init所生成的所有子进程都属 于同一个进程组.但是,同一个进程组的父子进程可能在信号上有相 互通讯,若父进程先于子进程退出系统,则子进程会成为一个孤儿进 程,可能变成僵死进程.从而使该子进程在其不\愿意\的情况下退出 运行.为解决这个问题,子进程可以自己组成一个新的进程组,即调 用setpgrp()与原进程组脱离关系,产生一个新的进程组,进程组号 与它的进程号相同.这样,父进程退出运行后就不会影响子进程的当 前运行.

. 子进程信号处理

但是,单做上述处理还不能解决另一个困难,即子进程在退出运行 时,找不到其父进程(父进程已退出,子进程的父进程号改为1).发送 子进程退出信号后没有父进程做出响应处理,该子进程就不可能完 全退出运行,可能进入僵死状态.所以父进程在产生子进程前最好屏 蔽子进程返回信号的处理,生成子进程,在父进程退出运行后,子进 程返回则其进程返回信号的处理会由系统给出缺省处理,子进程就 可以正常退出.

3.3.2兄弟进程关系

. 交换进程号

对于信息协调方式的程序来说,各兄弟进程间十分需要相互了解进 程号,以便于信号处理机制.比较合理的方法是父进程生成一个共享 内存的空间,每个子进程都在启动时在共享内存中设置自己的进程 号.这样,当一个子进程要向另一个子进程发送信号或是因为其他原 因需要知道另一个子进程号时,就可以在共享内存中访问得到所需 要的进程号.

3.3.3僵尸进程及如何处理子进程死亡

3.3.3.1僵尸进程

僵尸(Zombie)进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。

当一个进程已退出,但其父进程还没有调用系统调用wait(稍后介绍)对其进行收集之前的这段时间里,它会一直保持僵尸状态。

僵尸进程的概念是从UNIX上继承来的,而UNIX的先驱们设计这个东西并非是因为闲来无聊想烦烦其他的程序员。僵尸进程中保存着很多对程序员和系统管理员非常重要的信息,首先,这个进程是怎么死亡的?是正常退出呢,还是出现了错误,还是被其它进程强迫退出的?其次,这个进程占用的总系统CPU时间和总用户CPU时间分别是多少?发生页错误的数目和收到信号的数目。这些信息都被存储在僵尸进程中,试想如果没有僵尸进程,进程一退出,所有与之相关的信息都立刻归于无形,而此时程序员或系统管理员需要用到,就只好干瞪眼了。

收集这些信息,并终结这些僵尸进程靠waitpid调用和wait调用等方法完成。 僵尸进程虽然对其他进程几乎没有什么影响,不占用CPU时间,消耗的内存也几乎可以忽略不计,但有它在那里呆着,还是让人觉得心里很不舒服,同时Linux系统中进程数目是有限制的,在一些特殊的情况下,如果存在太多的僵尸进程,也会影响到新进程的产生。

for(int i=0;i<10;i++) if( fork==0) exit(0);

3.3.3.2处理子进程死亡的四种方法

3.3.3.2.1 忽略SIGCHLD信号.(只在Linux使用);

struct sigaction act,oldact; act.sa_handler=SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags=0;

if(sigaction(SIGCHLD,&act,&oldact)<0)

exit(1);

内核负责清除进程表项。(Linux only)

3.3.3.2.2 调用wait()或waitpid(); pid_t wait(int* statloc);

pid_t waitpid(pid_t pid,int* statloc,int option);

前者等待任意一个子进程结束,后者等待特定子进程结束; 函数返回子进程号,statloc返回exit的参数。

Wait: 进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的

某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

参数statloc用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(绝大多数情况下如此),我们就可以设定这个参数为NULL,即:

pidx = wait(NULL)

如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。

Waitpid: 从本质上讲,系统调用waitpid和wait的作用是完全相同的,但waitpid

多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式。

Pid:是一个进程ID。当pid取不同的值时,有不同的意义:

pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运

行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。

pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait

的作用一模一样。 pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进

程组,waitpid不会对它做任何理睬。 pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid

的绝对值。

Options:目前在Linux中只支持WNOHANG和WUNTRACED两个选项,可以用\运算符把

它们连接起来使用,如:

ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);

WNOHANG,表示即使没有子进程退出,它也会立即返回,不会像wait那样永远

等下去。 WUNTRACED,与跟踪调试有关,极少用到。 我们也可以把options设为0,如:

ret=waitpid(-1,NULL,0);

waitpid的返回值比wait稍微复杂一些,一共有3种情况:


c语言多进程多线程编程(6).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:在公司薪酬改革动员会上的讲话

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: