标签搜索

目 录CONTENT

文章目录

进程控制.md

小小城
2021-08-22 / 0 评论 / 0 点赞 / 3 阅读 / 2,474 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

进程控制

@[toc]

一、进程创建:

  •  1.Linux中fork函数可以从已存在的进程中创建一个新进程。新进程为子进程,而原来的进程为父进程
  •  2.原型
#include <unistd.h>

pid_t  fork(void);
  • 返回值:子进程中返回0;父进程中返回子进程pid,创建失败返回-1
  •  3.原理:
    进程调用fork后,内核做:
  • a.分配新的内存块和内核数据结构给子进程。
  • b.将父进程pcb部分数据结构拷贝至子进程。
  • c.并将子进程pcb放到内核管理的双向链表上。
  • d.fork返回,内核调度器开始调度

在这里插入图片描述
注意

  • 1.拷贝的子进程的执行流是和父进程的执行流是一致的,不会把拷贝过去父进程的代码给重新开始执行,因为PCB中有描述进程信息的程序计数器和上下文信息,这些也都拷贝给子进程了,所以子进程的执行流也是从fork的下一句开始执行,不会从代码的开始执行。
  • 2.子进程拷贝父进程pcb的方式是写实拷贝。通常父子进程代码是共享的,父子不再写入时,数据也是共享的,当任意一方尝试写入是,操作系统内核会从新为其开辟一个内存空间存储数据,这也就是前面说的创建子进程时,代码共享数据独有的原因,采用写时拷贝既可以节省内存,也可以提高操作系统运行效率,就不用每次花费时间去拷贝数据了
  • 3.fork失败的原因:
  • 系统中有太多的进程
  • 实际用户的进程数超过了限制

二、进程终止:

  •  1.进程退出的场景:
  • 代码运行完毕,结果正确,从main函数return 0退出。
  • 代码运行完毕,结果不正确,从main函数return 0退出。
  • 代码异常终止,程序中途退出
  •  2.进程正常退出的方法:(可以通过 echo $? 查看进程退出码)
  • a.从main函数的return 0退出
  • b.调用库函数exit
  • c.调用系统调用_exit
  •  3.进程异常退出:
  • ctrl+c/解引用空指针等
  •  4.exit函数和_exit函数的区别:
  • exit函数:
#include <unistd.h>

void  exit(int status);           
  • _exit函数:
#include <unistd.h>
void _exit(int status);

在这里插入图片描述
所以exit是封装了库函数_exit,但exit还有如下功能,而_exit没有

  • a.exit会执行用户自定义的清理函数
  • b.关闭所有打开的流,冲涮缓冲区

三、进程等待:

  •  1.进程等待的必要性:
  • 我们都知道僵尸进程产生的原因,即子进程先与父进程退出,而父进程没有获取子进程的退出状态,没有回收子进程的资源,所以会产生僵尸进程
  • 而前面我没 解决僵尸进程的方法是kill掉僵尸进程的父进程,现在我们采用进程等待的方法来解决僵尸进程的问题
  •  2.进程等待的方法:
  • a.函数原型
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
  • 返回值:
成功返回被等待进程pid,失败返回-1。
  • 参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
  • b.函数原型
pid_ t waitpid(pid_t pid, int *status, int options);
  • 返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;

如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;

如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
  • 参数:

pid:

Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。

status:

WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

options:

WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,
不予以等待。若正常结束,则返回该子进程的ID。

注意:

  • 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。

  • 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。

  • 如果不存在该子进程,则立即出错返回

  •  3.进程的status:

  • 首先,这里的status是输出型参数,是进程的状态信息而不是进程退出码,status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):

在这里插入图片描述

  • 测试获取进程状态信息的代码
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main( void )
{
	pid_t pid;
	if ( (pid=fork()) == -1 )
		perror("fork"),exit(1);
	
	if ( pid == 0 )
	{
		sleep(20);
		exit(10);
	} 
	else 
	{
		int st;
		int ret = wait(&st);
		if ( ret > 0 && ( st & 0X7F ) == 0 )
		{ 
			// 正常退出
			printf("child exit code:%d\n", (st>>8)&0XFF);
		} 
		else if( ret > 0 ) 
		{ 
			// 异常退出
			printf("sig code : %d\n", st&0X7F );
		}
	}
}

测试结果:
[root@localhost linux]# ./a.out #等20秒退出
child exit code:10

[root@localhost linux]# ./a.out #在其他终端kill掉
sig code : 9

0

评论区