进程1——进程与线程——day09

今天,主要讲一下进程的一些基本概念和一些接口

首先是进程的基本概念:

1.进程:

程序:存放在外存中的一段数据组成的文件
进程:是一个程序动态执行的过程,包括进程的创建、进程的调度、进程的消亡

2.进程相关命令:

1.top
  动态查看当前系统中的所有进程信息(根据CPU占用率排序)

    PID:唯一识别进程的ID号(>0)
    优先级:Linux系统中数据高,优先级高(-20 - 19)  Windows系统中数值高,优先级高
    进程状态: 
        R   运行态/就绪态
        S   睡眠态/可唤醒等待态
        D   不可唤醒等待态
        T   暂停态
        Z   僵尸态
        X   结束态

    q退出 
2.nice
  以指定优先级来运行进程

  示例:
    nice -n 优先级 要执行的集成任务

  renice 
  重新设定一个正在运行的进程的优先级
  
  示例:
    renice -n 优先级 进程PID 
3.kill
  杀死指定的进程任务

  示例:
    kill -9 进程PID 

  killall 
  杀死进程名对应的所有进程任务

  示例:
    killall -9 进程名 
4.ps -ef
  查看当前时刻所有进程的信息

  PPID:父进程的ID号 

  ps -ef | grep a.out 
5.pstree
  查看进程树关系
6.ps -aux
  查看当前时刻的进程信息
7…/a.out &
  将a.out任务放在后台执行
8.jobs
  查看一个终端下后台执行的所有任务
9.fg 编号
  将后台任务放到前台执行

3.进程的创建

     这里我们以32bits的操作系统做概括
     一个进程在运行时,操作系统会为该进程分配 0 - 4G 虚拟内存空间,分为文本段、数据段、系统数据段

文本段:
  也称为文本区,存放代码和指令

数据段:
  也称为数据区,可以细分为:
        1.字符串常量区
        2.未初始化全局变量/静态变量
        3.已初始化全局变量/静态变量 

系统数据段:
  包含堆区和栈区

在这里插入图片描述

4.进程中虚拟地址和物理地址的关系

1. 0 - 4G虚拟内存空间只有一个
2. 实际物理地址中每个进程空间独立
3. 通过MMU内存映射单元,单一个进程执行时,将物理地址中的数据加载到虚拟地址中运行

5.进程的调度:

1.常见的调度算法:
  1.先来先执行,后来后执行
  2.高优先级调度算法
  3.时间片轮转调度算法
  4.多级队列反馈调度算法
  5.负载均衡调度算法

  时间片:
    1.CPU在一个任务中的运行时间称为一个时间片
2.宏观并行,微观串行
3.进程的状态:
    R     运行态、就绪态 
    S     睡眠态/可唤醒等待态 
    D     不可唤醒等待态 
    T     暂停态
    Z     僵尸态
    X     结束态

6.进程相关函数接口:

1.进程的创建
fork
  pid_t fork(void);
  功能:
    创建一个子进程,新创建的进程称为原来进程的子进程,原来的进程称为新进程的父进程
  参数:
    void 缺省
  返回值:
    成功子进程返回0 
    父进程返回子进程的PID 
    失败返回-1 

   父进程调用fork创建子进程,子进程拷贝父进程的文本段、数据段、系统数据段  
getpid
  pid_t getpid(void);
  功能:
    获得调用进程的PID号
  
  getppid
  pid_t getppid(void);
  功能:
    获得调用进程的PPID

练习:
创建一个父进程的2个子进程,子进程中打印自己的PID和父进程的PID
父进程中打印自己的PID和两个子进程的PID

#include"head.h"

int main(void)
{
	pid_t pid1;
	pid_t pid2;

	pid1 = fork();

	if(-1 == pid1)
	{
		perror("fail to fork");
		return -1;
	}

	if(0 == pid1)
	{
		printf("Child1 Process PID:%d PPID:%d\n",getpid(),getppid());
	}else if(pid1 > 0)
	{
		pid2 = fork();

		if(-1 == pid2)
		{
			perror("fail to fork");
			return -1;
		}
		
		if(0 == pid2)
		{
			printf("Child2 Process PID:%d PPID:%d\n",getpid(),getppid());
		}else if(pid2 > 0)
		{
			printf("Parent Process PID:%d Child PID1:%d PID2:%d\n",
					getpid(),pid1,pid2);
		}
	}

	while(1)
	{

	}

	return 0;
}

结果:
在这里插入图片描述

2.exit
void exit(int status);
功能:
  让进程结束
参数:
  status:进程结束的状态
返回值:
  缺省

exit在主函数中使用和return效果一致
exit会刷新缓存区

_exit
void _exit(int status);
功能:
  让进程直接结束
参数:
  status:进程结束的状态
返回值:
  缺省

7.进程的消亡

1.僵尸进程:
进程代码执行结束,空间没有被回收,称为僵尸进程
2.如何避免产生僵尸进程?
1.让父进程先结束
2.让父进程回收子进程空间
3.孤儿进程:
  进程的父进程先结束,此时该进程称为孤儿进程,被系统进程收养,进程再结束时,会被系统进程回收进程空间

8.wait

pid_t wait(int *wstatus);
功能:
	回收子进程空间
参数:
	wstatus:存放子进程结束状态空间的首地址
返回值:
	成功返回回收到的子进程PID
 	失败返回-1 
1.wait函数具有阻塞功能
2.wait函数具有同步功能
WIFEXITED(wstatus)
进程是否正常退出 

WEXITSTATUS(wstatus)
进程结束状态值

WIFSIGNALED(wstatus)
进程是否被信号杀死

WTERMSIG(wstatus)
获得杀死进程的信号编号

我们可以举一个例子,来检测该进程是否为正常结束

#include"head.h"

int main(void)
{
	pid_t pid;
	pid_t ret;
	int wstatus;

	pid = fork();

	if(-1 == pid)
	{
		perror("fail to fork");
		return -1;
	}

	if(0 == pid)
	{
		printf("Child Process start! PID:%d PPID:%d\n",getpid(),getppid());
		sleep(10);
		printf("Child Process ending!\n");
		exit(10);
	}else if(pid > 0)
	{
		printf("Parent Process start! PID:%d\n",getpid());
		ret = wait(&wstatus);
		if(-1 == ret)
		{
			perror("fail to wait");
			return -1;
		}

		printf("Reclaim to %d subprocess space \n",ret);

		if(WIFEXITED(wstatus))
		{
			printf("Normal end with a value of %d\n",WEXITSTATUS(wstatus));
		}else if(WIFSIGNALED(wstatus))
		{
			printf("Killed by the %d signal\n",WTERMSIG(wstatus));
		}
	}

	return 0;
}

如果为正常结束:
在这里插入图片描述
但是如果在进程工程中杀死该子进程,则会出现:
在这里插入图片描述
在这里插入图片描述
表示该进程被信号为9的编号杀死

以上就是今天内容,谢谢大家

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值