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

2019-08-02 01:35

1) 正常返回的时候,waitpid返回收集到的子进程的进程ID;

2) 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可

收集,则返回0; 3) 调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在。

例如:当pid所指示的子进程不存在,或此进程存在,但不是调用进程的

子进程,waitpid就会出错返回,这时errno被设置为ECHILD;

3.3.3.2.3 捕获SIGCHLD信号,在处理函数中调用wait()或waitpid().

void sigchld_handler(int signo) {

pid_t pid; int stat;

while( (pid=waitpid(-1,&stat,WNOHANG))>0 )

{} return; }

void main() {

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

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

…… } }

3.3.3.2.4 两次调用fork().

第一次调用fork()产生的子进程的主进程,调用exit(0), 第二次调用fork()产生的子进程成为孤儿(orphaned process)进程,交给init管理,孤儿进程退出时.系统会把它清理干净。

int main() {

int i;

pid_t pid; pid=fork(); if(pid==0)

{ for(i=0;i<5;i++) {

if(fork(0)==0) { sleep(1); exit(0); } }

exit(0);

}

for(;;){}

}

总结:进程的一生

随着一句fork,一个新进程呱呱落地,但它这时只是老进程的一个克隆。 然后随着exec,新进程脱胎换骨,离家独立,开始了为人民服务的职业生涯。

人有生老病死,进程也一样,它可以是自然死亡,即运行到main函数的最后一个\,从容地离我们而去;也可以是自杀,自杀有2种方式,一种是调用exit函数,一种是在main函数内使用return,无论哪一种方式,它都可以留下遗书,放在返回值里保留下来;它还甚至能可被谋杀,被其它进程通过另外一些方式结束他的生命。

进程死掉以后,会留下一具僵尸,wait和waitpid充当了殓尸工,把僵尸推去火化,使其最终归于无形。

3.3.4守护进程

Linux有三种进程:核心进程、守护进程、用户进程。 守护进程在后台运行,如:打印管理程序、http服务器 Linux的大多数服务器就是用守护进程实现的。

守护进程的编程要点

不同Unix环境下守护进程的编程规则并不一致,但守护进程的编程原则其实都一样,区别在于具体的实现细节不同。这个原则就是要满足守护进程的特性。同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下; 1. 在后台运行

在进程中调用fork后,使父进程终止,让Daemon在子进程中后台执行。

if(pid=fork())

exit(0);//是父进程,结束父进程,子进程继续

2. 脱离控制终端,登录会话和进程组

进程与控制终端,登录会话和进程组之间的关系:

进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。 登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。会话过程对控制终端具有独占性

由于控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第1点的基础上,调用setsid()使进程成为会话组长: setsid();

说明:当进程是会话组长时setsid()调用失败。

第一点已经保证进程不是会话组长。 setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离,同时与控制终端脱离。

1. 忽略SIGHUP,再次调用fork(),然后父进程退出。

目的:禁止进程重新打开控制终端

现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:

if(pid=fork())

exit(0);//结束第一子进程,第二子进程继续(第二子进程不再是会话组长)

2. 关闭打开的文件描述符

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下,以及引起无法预料的错误。按如下方法关闭它们:

for(i=0;i 关闭打开的文件描述符close(i);)

3. 改变当前工作目录

进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如/tmpchdir(\

4. 重设文件创建掩模

进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0),使得进程具有完全的写权限;

5. 处理SIGCHLD信号

处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN。 signal(SIGCHLD,SIG_IGN);

这样,内核在子进程结束时不会产生僵尸进程。

守护进程实例

这个守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态。

初始化程序中的init_daemon函数负责生成守护进程。可以利用init_daemon函数生成自己的守护进程。 1. init.c清单

#include < unistd.h >

#include < signal.h > #include < sys/param.h > #include < sys/types.h > #include < sys/stat.h > void init_daemon(void) {

int pid; int i;

if(pid=fork())

exit(0);//是父进程,结束父进程 else if(pid< 0)

exit(1);//fork失败,退出

//第一子进程,在后台继续执行

setsid(); //第一子进程成为新的会话组长和进程组长 //并与控制终端分离

if(pid=fork())

exit(0); //是第一子进程,结束第一子进程 else if(pid< 0)

exit(1); //fork失败,退出

//第二子进程,继续

//第二子进程不再是会话组长

for(i=0;i< NOFILE;++i)//关闭打开的文件描述符

close(i);

chdir(\改变工作目录到/tmp umask(0);//重设文件创建掩模 return; }

2. test.c清单

#include < stdio.h > #include < time.h >

void init_daemon(void);//守护进程初始化函数 main() {

FILE *fp;

time_t t;

init_daemon();//初始化为Daemon

while(1)//每隔一分钟向test.log报告运行状态 {

sleep(60);//睡眠一分钟

if((fp=fopen(\ {

t=time(0);

fprintf(fp,\ fclose(fp); } } }

编译:gcc -g -o test init.c test.c 执行:./test

查看进程:ps -ef

从输出可以发现test守护进程的各种特性满足上面的要求。

3.4.进程间通讯处理 3.4.1共享内存需要锁机制

由于共享内存在设计时没有处理锁机制,故当有多个进程在访问共享 内存时就会产生问题.如:一个进程修改一个共享内存单元,另一个进程在 读该共享内存单元时可能有第三个进程立即修改该单元,从而会影响程序 的正确性.同时还有分时系统对各进程是分时间片处理的,可能会引起不 同的正确性问题.按操作系统的运作方式,则有读锁和写锁来保证数据的 一致性.所以没有锁机制的共享内存,必须和信号量一起使用,才能保证共 享内存的正确操作.

3.4.2消息队列需要关键值

消息队列的操作在进程取得消息队列的访问权限后就必须通过关键 值来读消息队列中的相同关键值的消息,写消息时带入消息关键值.这样 可以通过不同的关键值区分不同的交易,使得在同一个消息队列可以供多 种消息同时使用而不冲突.若读消息队列使用关键值0则读取消息队列中 第一个消息,不论其关键值如何.

3.4.3信号需要信号处理函数设置和再设置

在用户进程需要对某个中断做自己定义的处理时,可以自己定义中断


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

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

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

马上注册会员

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