栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux编程基础:进程管理-2 进程同步 课后总结

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux编程基础:进程管理-2 进程同步 课后总结

目录

一、课堂内容

1、进程管理

2.进程同步

二、exec函数族

 三、进程退出

四、特殊进程及其危害 

五、进程同步

1.wait()函数

 2.waitpid()函数


一、课堂内容

1、进程管理

exec函数族

进程退出

特殊进程及其危害

2.进程同步

wait()函数

waitpid()函数

二、exec函数族

1.与fork()函数的区别

fork()函数:子进程复制父进程的堆栈段和数据段,子进程一旦开始运行,它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再影响
exec()函数:一个进程调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序代码,废弃原有数据段和堆,并为新程序分配新数据段与堆栈段
exec函数族中包含6个函数,分别为:

#include 
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char * const argv[]);
int execvp(const char *file, char * const argv[]);
int execve(const char *path, char * const argv[], char * const envp[]);


参数说明:
(1)当参数是path,传入的为路径名;当参数是file,传入的可执行文件名;
(2)可以将exec函数族分为execl和execv两类:

execl类:函数将以列举的形式传入参数,由于参数列表的长度不定,所以要用哨兵NULL表示列举结束;
execv类:函数将以参数向量表传递参数,char * argv[]的形式传递文件执行时使用的参数,数组中最后一个参数为NULL;
(3)如果没有参数char * const envp[],则采用默认环境变量;如果有,则用传入的参数替换默认环境变量;

2.代码案例

#include 
#include 
#include 
int main(){
    pid_t tempPid;
    tempPid=fork();
    if(tempPid == -1){   
        perror("fork error");
        exit(1);
    } else if(tempPid > 0) {   
        printf("parent process:pid=%dn", getpid());
    } else {   
        printf("child process:pid=%dn", getpid());
        //execl("/bin/ls","-a","-l","test_exec.c",NULL);
        //execlp("ls","-a","-l","test_exec.c",NULL);
        char *arg[]={"-a","-l","test_exec.c", NULL};
        execvp("ls", arg);
        perror("error execn");
        printf("child process:pid=%dn", getpid());
    } 
    return 0;
}

3.运行结果

 三、进程退出
#include 
void exit(int status);

参数说明:
(1)status:表示进程的退出状态,0表示正常退出,非0表示异常退出,一般用-1或1表示;
(2)为了可读性,标准C定义了两个宏:EXIT_SUCCESS和EXIT_FAILURE

Linux系统中有一个与exit()函数非常相似的函数:_exit()

#include 
void _exit(int status);

区别:

_exit:系统会无条件停止操作,终止进程并清除进程所用内存空间及进程在内核中的各种数据结构;

exit:对_exit进行了包装,在调用_exit()之前先检查文件的打开情况,将缓冲区中的内容写回文件。相对来说exit比_exit更为安全

 

四、特殊进程及其危害 

1.孤儿进程

        父进程负责回收子进程,如果父进程在子进程退出之前退出,子进程就会变成孤儿进程,此时init进程将代替父进程完成子进程的回收工作


2.僵尸进程

        调用exit函数后,该进程不会马上消失,而是留下一个称为僵尸进程的数据结构。它几乎放弃进程退出前占用的所有内存,既没有可执行代码也不能被调度,只是在进程列表中保留一个位置,记载进程的退出状态等信息供父进程回收。若父进程没有回收子进程的代码,子进程将会一直处于僵尸态。

3.危害

        僵尸进程不能再次被运行,会占用一定的内存空间,并占据进程编号,当僵尸进程较多时,将会消耗系统内存,新进程可能因内存不足或无法获取pid而无法创建;
        父进程通过wait()和waitpid()函数可以有效防止僵尸进程的产生,对于已存在的僵尸进程,则可通过杀死其父进程的方法解决;
        当僵尸进程的父进程被终止后,僵尸进程将作为孤儿进程被init进程接收,init进程会不断调用wait()函数获取子进程状态,对已处于僵尸态的进程进行处理;
        孤儿进程永远不会成为僵尸进程。

五、进程同步

1.wait()函数

子进程结束时,系统向其父进程发送SIGCHILD信号
父进程调用wait函数后阻塞
父进程被SIGCHILD信号唤醒然后去回收僵尸子进程
若没有变为僵尸态的子进程,wait函数就会让进程一直阻塞。
只要捕获到一个变为僵尸态的子进程,wait函数就会恢复执行态。
若父进程没有任何子进程则wait返回错误。

参数说明:参数status是一个int *类型的指针,用来保存子进程退出时的状态信息。通常情况下该参数设为NULL,表示不关心进程时如何终止的。

返回值说明:

  • 成功:返回子进程的进程id;
  • 失败:返回-1,errno被设置为ECHILD

代码案例【1】:若子进程p1 是其父进程p的先决进程,基于wait函数使得进程同步

#include 
#include 
#include 
int main(){
	pid_t tempPid, tempW;
	tempPid = fork();
	if(tempPid == -1){
		perror("fork error");
		exit(1);
	}else if(tempPid == 0){
		sleep(3);
		printf("Child process, pid = %d, ppid = %dn", getpid(), getppid());
	}else{ 
		tempW = wait(NULL);
		printf("Catched a child process, pid = %d, ppid = %dn", tempW, getppid());
	}
	printf("......finish......");
	return 0;
}

运行结果:

 代码案例【2】:使用wait同步进程,并使用宏获取子进程的返回值

#include 
#include 
#include 
int main(){
    int tempStatus;
    pid_t tempPid, tempW;
    tempPid = fork();
    if(tempPid == -1){
        perror("fork error");
        exit(1);
    } else if(tempPid == 0){
        sleep(3);
        printf("Child process: pid=%dn",getpid());
        exit(5);
 	}  else{
        tempW = wait(&tempStatus);
        if(WIFEXITED(tempStatus)){
            printf("Child process pid=%d exit normally.n", tempW );
            printf("Return Code:%dn",WEXITSTATUS(tempStatus));
        } else {
            printf("Child process pid=%d exit abnormally.n", tempW);
        }
    }
    return 0;
}

运行结果:

 2.waitpid()函数
#include 
pid_t waitpid(pid_t pid, int *status, int options);

功能:
        对wait()函数来说,若当前进程有很多个子进程,则其无法保证所有子进程在父进程之前执行。而waitpid()函数可以应对 wait函数面临的缺点。可以等待指定的子进程,也可以在父进程不阻塞的情况下获取子进程的状态。
 

参数说明:

pid:一般是进程的pid,也有可能是其他取值。进一步说明如下:
– pid > 0:等待子进程(编号为pid)退出,若退出,函数返回;若未结束,则一直等待;
– pid = 0:等待同一进程组的所有子进程退出,若某子进程加入了其他进程组,则waitpid不再关心它的状态;
– pid = -1:waitpid函数退化为wait函数,阻塞等待并回收一个子进程;
– pid < -1:等待指定进程组中的任何子进程,进程组的id等于pid的绝对值。
options: 提供控制选项,可以是一个常量,也可以是|连接的两个常量,选项如下:
– WNOHANG:如果子进程没有终止,waitpid不会阻塞父进程,会立即返回;
– WUNTRACED:如果子进程暂停执行,waitpid立即返回;
– 0:不使用选项。
 

返回值说明:
成功:返回捕捉到的子进程id;
0:options = WNOHANG, waitpid发现没有已退出的子进程可回收;
-1:出错,errno被设置。

代码案例【1】:父进程等待进程组中指定子进程,该进程不退出,则父进程一直阻塞。

test_waitpid.c
#include 
#include 
#include 
int main(){
	pid_t tempPid, tempP, tempW;
	tempPid= fork();
	if (tempPid == -1){							
		perror("fork1 error");
		exit(1);
	} else if (tempPid == 0){
		sleep(5);
		printf("First child process:pid=%dn", getpid());
	} else {
		int i;
		tempP = tempPid;
		for (i = 0; i < 3; i++){
			if ((tempPid = fork()) == 0){
				break;
			}
		}
		if (tempPid == -1){
			perror("fork error");
			exit(2);
		} else if (tempPid == 0){
			printf("Child process:pid=%dn", getpid());
			exit(0);
		} else {
			tempW = waitpid(tempP, NULL, 0);
			if (tempW == tempP){
				printf("Catch a child Process: pid=%dn", tempW);
			}else{
				printf("waitpid errorn");
			}
		}
	}
	return 0;
}

运行结果:

 代码案例【4】:基于waitpid函数不断获取子进程的状态。

#include 
#include 
#include 
int main() {
	pid_t tempPid, tempW;
	tempPid = fork();
	if (tempPid == -1){
		perror("fork error");
		exit(1);
	} else if (tempPid == 0){
		sleep(3);
		printf("Child process:pid=%dn", getpid());
		exit(0);
	} else {
		do{
			tempW = waitpid(tempPid, NULL, WNOHANG);
			if (tempW == 0){
				printf("No child exitedn");
				sleep(1);
			}
		} while (tempW == 0);
		if (tempW == tempPid){
			printf("Catch a Child process:pid=%dn", w);
		}else{
			printf("waitpid errorn");
		}
	}
	return 0;
}

运行结果:

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/881971.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号