day25 进程

概念

是程序的一次执行过程,是调度和资源分配的独立单元,是资源分配的最小单位

进程和程序的区别

进程:是动态的,在内存上,包含创建、调度和消亡

程序:是静态的,在硬盘上

CPU的调度机制

时间片轮转机制:cpu以ms级速度在多个进程之间来回切换

进程的五态图

 阻塞态不能直接回到运行态!!!

 进程的标识

一个终端打开时,会有一个会话id,其包含一个前台进程组,多个后台进程组,一个进程组包含多个进程

pid: process id 进程id

ppid: parent process id 父进程id

pgid: process group id 进程组id

SID:session id 会话id

三个特殊进程号

0:indel进程,操作系统的引导进程

1:init进程,初始化进程,收养孤儿进程

2:kthread进程,用户进程线程之间调度

shell指令

ps -ef          查看每个进程

ps -aux       查看进程的内存的使用情况

ps -ajx        打印进程树

ps -ajx | grep a.out        查找a.out进程,进程树的形式输出

|:  管道符,上一个指令的输出作为下一个指令的输入

grep a.out:  查找a.out进程

pidof 进程名    查看指定进程id号

进程的状态

               D    不可中断的休眠态(usually IO)
               R    运行态(on run queue)
               S    可中断的休眠
               T    挂起态
               t    bug调制状态
               W    分页
               X    死亡态 (should never be seen)
               Z    僵尸

       For BSD formats and when the stat keyword is used,
       additional characters may be displayed:

               <    高优先级 (对其他用户不友好)
               N   第优先级(对其他用户友好)
               L    将页面锁定在内存
               s    会话领导者
               l    多线程
               +    运行在前端

进程的内存

操作系统指针虚拟内存大小
324字节2^32--->4G
638字节2^48--->256TB        虚拟内存没那么多,取48位

内核与用户空间划分3:1

 堆和栈的区别

0.申请和释放 存放内容 地址方向 空间大小 碎片化程度

1.堆区空间用户申请和释放,栈区空间计算机自动申请和释放

2.堆区存放malloc申请的空间,栈区存储局部变量

3.地址方向不同:堆区从低到高,栈从高到低

4.堆区空间2G-3G,栈区空间8M

5.堆区碎片化严重,栈区基本没有碎片化

堆栈溢出

空间不足,递归层数较多时,计算机不断申请栈区空间,此时可能会空间不足

内存泄漏

堆区申请的空间已经不使用了,但是未释放

进程相关函数

frok

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

功能:创建子进程,子进程拷贝父进程的用户空间

参数:无

返回值:成功进程返回子进程的pid

              进程返回0

              失败返回-1,更新errno

用户空间:堆区,栈区,静态区,缓冲区,文件描述符

内核空间共享(光标:打开文件一次,子进程拷贝父进程,光标共享)

n次fork后:2^n个进程

父子进程执行顺序不固定,sleep()放弃cpu资源

写实拷贝

子进程拷贝父进程的用户空间

不发生数据改变时,父子进程共享同一物理内存页

当一个进程发生数据改变时,内核会触发缺页异常,此时才会分配新的物理页,复制内容,解除写保护,此后,父子进程才各自拥有独立的副本。

作用:高效性,节省资源

getpid | getppid

#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);
pid_t getppid(void);

功能:顾名思义,获取调用者pid或ppid

参数:无

返回值:成功返回调用者的pid或ppid  不会失败

 exit

#include <stdlib.h>

void exit(int status);

功能:退出进程,并把退出状态值返回给父进程

库函数调用,刷新缓冲区

参数:int status  退出状态值,人为规定0表示正常退出,一般写0

返回值:无

status        退出状态值,一般正常退出为0,异常退出为非0

_exit

#include <unistd.h>

       void _exit(int status);

功能:退出进程,并把退出状态值返回给父进程

系统调用,不刷新缓冲区

参数:int status  退出状态值,人为规定0表示正常退出,一般写0

返回值:无

wait

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *wstatus);

功能:阻塞函数,等待任意子进程退出,回收子进程资源(回收僵尸资源)接收exit的退出状态值

参数:int *wstatus  该指针指向内存中存储exit的退出状态值

                NULL       不接收exit的退出状态值

返回值:

                成功返回接收子进程的pid,失败返回-1,更新errno

WEXITSTATUS(wstatus) 计算退出状态值的 (status&0xff00)>>8

waitpid

pid_t waitpid(pid_t pid, int *wstatus, int options);

功能:阻塞函数(可非阻塞),等待任意子进程退出,回收子进程资源(回收僵尸资源)接收exit的退出状态值

参数:

          pid_t  pid

                

<-1等待进程组id等于pid绝对值的进程组下的任意子进程
-1等待当前进程的任意子进程结束  等价于wait
0等待当前进程的任意子进程结束
>0等待回收指定子进程

          int *wstatus  该指针指向内存中存储exit的退出状态值

                NULL       不接收exit的退出状态值

          int options     0:阻塞

                                WNOHANG:设置为非阻塞

返回值:

                成功返回接收子进程的pid,失败返回-1,更新errno

#include <25061head.h>
int main(int argc, const char *argv[])
{		
	pid_t pid=fork();
	if(pid>0)
	{
		int status; //定于退出状态值
		pid_t ret=wait(&status); //ret接收返回值
		printf("%d pid::%d ret::%d  status=%d\n",__LINE__,getpid(),ret,WEXITSTATUS(status));	
		//status为0是因为此处为信号中断,低八位为0,宏函数返回值为0
		if(WIFEXITED(status))  //是否为异常退出
		{
			printf("正常退出\n");
		}
		else
		{
			printf("异常退出\n");
			printf("%d\n",status); //139
			printf("%d\n",WEXITSTATUS(status));  //0
		}
		int sig;
		sig=WTERMSIG(status);
		printf("%d\n",sig);
		if(sig=WTERMSIG(status))  //是否为信号中断
		printf("%d信号中断\n",sig);
	}
	else if(pid==0)
	{
		printf("%d pid::%d \n",__LINE__,getpid());
		kill(getpid(), SIGSEGV); 
		int *p=NULL;
		*p=100;
		exit(7);
	}
	else
	{
		ERR_MSG("FORK ERROR");
	}
	return 0;
}

vfork

同fork 区别子进程共享父进程的地址空间  子进程先运行,父进程阻塞

宏函数

WIFEXITED(wstatus)       

判断是否是异常退出的,如果正常退出则返回真,否则返回假

WEXITSTATUS(wstatus)计算退出状态值的 (status&0xff00)>>8

WTERMSIG(wstatus)

判断是否是信号中断的, 如果是信号中断则返回真(信号编号)

进程扇

#include <25061head.h>
void pid_create(int n)
{
	for(int i=1;i<=n;i++)
	{
		pid_t pid =fork();
		if(pid==0) //子进程
		{   
			sleep(i); //确保顺序输出
			printf("子进程%d pid=%d ppid=%d\n",i,getpid(),getppid());
			//关闭子进程
			sleep(n-i+1); //统一时间关闭
			exit(0);
		}
	}
}
int main(int argc, const char *argv[])
{		
	int n;
	printf("需要创建几个子进程\n");
	scanf("%d",&n);
	pid_create(n);
	//回收子进程
	pid_t pid2;
	while((pid2=wait(NULL))!=-1)
	printf("pid=%d子进程回收\n",pid2);	
	printf("父进程 pid=%d\n",getpid());
	return 0;
}

 进程链

#include <25061head.h>
void pid_create(int n)
{
		static int i=1;
		pid_t pid =fork();
		if(n==1&&pid==0)  //递归出口
		{
			printf("子进程%d代 pid=%d 父进程ppid=%d\n",i,getpid(),getppid());
			exit(0);
			return ;
		}
		if(pid==0) //子进程
		{   
			printf("子进程%d代 pid=%d 父进程ppid=%d\n",i++,getpid(),getppid());
			pid_create(n-1);
			_exit(0);
		}
		else  //父进程
		wait(NULL);//回收子进程			
	}
int main(int argc, const char *argv[])
{		
	int n;
	printf("需要创建几个子进程\n");
	scanf("%d",&n);
	printf("父进程 pid=%d\n",getpid());
	pid_create(n);
	printf("父进程 pid=%d结束\n",getpid());
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值