10.2 Linux_进程_进程相关函数

创建子进程

函数声明如下:

cpp 复制代码
pid_t fork(void);

返回值:失败返回-1,成功返回两次,子进程获得0(系统分配),父进程获得子进程的pid

注意:fork创建子进程,实际上就是将父进程复制一遍作为子进程,但子进程只执行fork之后的代码,不执行fork之前的代码。这里的"复制"代表了父子进程的空间是独立的,互不影响。

孤儿进程与僵尸进程:

如果父进程先结束,那么子进程变成孤儿进程,最终被init进程收养,并且子进程变为后台进程。

如果子进程先结束,但父进程没有回收子进程,那么子进程变成僵尸进程。

fork基本使用方法:

cpp 复制代码
pid = fork();
if(pid<0){
    perror("fork");
    return -1;
}else if(pid == 0){
    //子进程代码
}else if(pid > 0){
    //父进程代码
}

创建多个子进程:

具体代码实现如下:

cpp 复制代码
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(){

	pid_t pid;
	int i;
	printf("father pid = %d\n",getpid());
	for(i=0;i<5;i++){
		if((pid=fork()) < 0){
			perror("fork");
			return -1;
		}else if(pid == 0){
			break;//子进程不进行fork
		}
	}
	if(i==5){
		printf("father pid = %d\n",getpid());
	}
	else{
		printf("child pid = %d\n",getpid());
	}
	while(1);

	return 0;
}

代码执行结果如下:

进程结束

函数声明如下:

cpp 复制代码
void exit(int status);

void _exit(int status);
void _Exit(int status);

exit结束进程后,会刷新缓冲区,其余这三个函数没有区别。

status:返回给系统的状态值

注意:main函数结束会隐式调用exit函数,所以在main函数结束时会刷新缓冲区。

exit刷新缓冲区实验:

进程回收

函数声明如下:

cpp 复制代码
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);

返回值:成功返回回收的子进程的pid,失败返回EOF

wstatus:保存子进程结束的状态,NULL代表直接释放子进程的PCB,不接收返回值。

pid:想要回收的子进程的pid,-1代表任意子进程,0代表进程组中的任意子进程

options:回收的方式

  • 0:阻塞等待子进程结束
  • WNOHANG:不阻塞等待子进程结束,子进程未结束也返回,继续执行下面代码。

注意:父进程调用该函数后一直处于阻塞状态,直到子进程结束

通过宏来解析wstatus:

wstatus中包含了是否正常退出、exit返回值、是否被信号结束、结束进程的信号类型。

解析的宏如下:

|----------------------|-------------------|
| 宏 | 含义 |
| WIFEXITED(wstatus) | 判断子进程是否正常退出 |
| WEXITSTATUS(wstatus) | 获取子进程返回值,即:exit的值 |
| WIFSIGNALED(wstatus) | 判断子进程是否被信号结束 |
| WTERMSIG(wstatus) | 获取结束子进程的信号类型 |

wait测试代码:

具体代码实现如下:

cpp 复制代码
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(){
	
	pid_t pid;
	int wstatus;

	if((pid = fork()) < 0){
		return -1;
	}else if(pid == 0){
		sleep(10);
		printf("now child exit\n");
		exit(2);
	}else{
		wait(&wstatus);//以阻塞方式等待子进程退出
		printf("是否正常退出:%d\n",WIFEXITED(wstatus));
		printf("子进程的返回值为%d\n",WEXITSTATUS(wstatus));
		printf("子进程是否被信号结束%d\n",WIFSIGNALED(wstatus));
		printf("结束子进程的信号类型%d\n",WTERMSIG(wstatus));
	}
	return 0;
}

代码执行结果如下:

waitpid填写WNOHANG实验:

当子进程退出后,子进程的pid会一直存在,直到被回收。当写入WNOHANG时,waitpid不会进入阻塞。但可以通过循环的模式,一次次判断是否有子进程需要回收。

具体代码实现如下:

cpp 复制代码
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(){
	
	pid_t pid;
	int wstatus;

	if((pid = fork()) < 0){
		return -1;
	}else if(pid == 0){
		sleep(5);
		printf("now child exit\n");
		exit(2);
	}else{
		while(1){
			if(waitpid(pid,&wstatus,WNOHANG) > 0){ //当子进程退出后,父进程退出while
				break;
			}
			printf("father is running\n");
			sleep(1);
		}
	}
	return 0;
}

代码执行结果如下:

进程执行其他程序

1、exec

exec函数的作用:

进程调用exec函数执行某个程序,调用后进程的当前内容被指定的程序替换,但进程号不变。

利用exec可以实现父子进程执行不同的程序:创建子进程->子进程调用exec执行其他功能。

函数声明如下:

cpp 复制代码
int execl(const char *pathname, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execv(const char *pathname, char *const argv[]);
int execvp(const char *file, char *const argv[]);

返回值:失败返回-1

pathname:执行程序的路径

file:执行程序的名字,会从环境变量PATH中寻找该执行程序

arg:执行程序的参数,第0个参数为程序名

argv:执行程序的参数,以字符串数组形式呈现

...:写NULL、0、(char*)0,这三个中的其中一个

示例:使用execl实现 " ls -li . " 的功能

具体代码实现如下:

cpp 复制代码
#include <unistd.h>
#include <stdio.h>

int main(){
    
    //ls -li . 有三个参数,ls是第0个参数
	execl("/bin/ls","ls","-li",".",NULL);
	printf("get\n");
	return 0;
}

代码运行结果如下:

示例:使用execv实现 " ls -li . " 的功能

具体代码实现如下:

cpp 复制代码
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main(){
	
    //这里最后一个NULL,不需要加双引号
	char* a[] = {"ls","-li",".",NULL};

	if(execv("/bin/ls",a) == -1){
		perror("execv");
	}
	printf("get\n");
	return 0;
}

代码运行与execl一样

2、system

system的作用:

执行一个指令,调用system后会等待指令执行结束,之后继续执行下面的代码,而不是像exec那样下面的代码被替代。

函数声明如下:

cpp 复制代码
int system(const char *command);

返回值:失败返回EOF

command:一个指令,以字符串形式呈现

示例:使用system实现 " ls -li . " 的功能

具体代码实现如下:

cpp 复制代码
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(){
	
	system("ls -li .");
	printf("get\n");
	return 0;
}

代码运行结果如下:

相关推荐
柱子子子子2 分钟前
Ubuntu24.04 不能使用todesk 解决办法
运维·服务器
天若有情67323 分钟前
新闻通稿 | 软件产业迈入“智能重构”新纪元:自主进化、人机共生与责任挑战并存
服务器·前端·后端·重构·开发·资讯·新闻
BJ_Bonree27 分钟前
圆桌论坛精华实录 | AI是重构运维逻辑的颠覆性革命?博睿数据与行业大咖亲授“AI+可观测性”的破局之道
运维·人工智能·重构
鱼干~28 分钟前
electron基础
linux·javascript·electron
apocelipes38 分钟前
POSIX兼容系统上read和write系统调用的行为总结
linux·c语言·c++·python·golang·linux编程
冬夜戏雪1 小时前
【尚庭公寓152-157】[第6天]【配置阿里云号码认证服务】
运维·服务器
恋上钢琴的虫1 小时前
openEuler上安装高版本的docker
运维·docker·容器
森语林溪1 小时前
大数据环境搭建从零开始(十四)CentOS 7 系统更新源更换详解:阿里云镜像源配置完整指南
大数据·linux·运维·阿里云·centos
Fanmeang2 小时前
华为交换机VLAN技术详解:从基础到高级应用
运维·网络·华为·vlan·交换机·mux vlan
Y淑滢潇潇2 小时前
RHCE Day3 DNS服务器
运维·服务器