Linux进程概念2

创建子进程

1.fork

#include <unistd.h> //头文件

pid_t fork(void)    //原型

如:

#include <stdio.h>
#include <unistd.h>

int main(){
	printf("输出一遍");
	fork();
	sleep(1);
	printf("输出两遍: pid:%d,ppid:%d\n",getpid(),getppid());
	sleep(1);
	return 0;
}

fork之后将会有两个子进程。
一个是原进程执行下来叫父进程,
一个是fork之后创建的子进程

fork有两个返回值
给父进程返回子进程的PID
调用成功给子进程返回0值,调用失败,给子进程返回-1

一般多进程的使用

#include <stdio.h>
#include <unistd.h>

int main(){
	pid_t ret=fork();
	if(ret > 0){
		//parent
	}
	else if(ret == 0){
		//child
	}
	else{
		printf("fork error\n");
	}
	sleep(1);
	return 0;
}

此时ret>0的情况与ret==0的两个不同判断语句的执行流都会执行,都会打印,在原来的单进程中不会都打印,在多进程中可以都打印
父进程与子进程如果是死循环,那也是两个死循环打印

父子进程代码共享,数据各自开辟空间,私有一份

2.关于fork的问题

如何理解进程创建?

在这里插入图片描述
创建进程是系统中多了一个进程,多了一个进程,就多了一个进程系统,就要多一组(管理进程的数据结构+该进程对应的代码和数据)

管理进程的数据结构我们现在只讲了task_struct,但实际创建一个进程需很多数据结构,代价是很高的

fork父子进程执行顺序和代码和数据复制问题,进程数据=代码+数据
1.父进程创建子进程的时候,代码是共享的,数据是各自私有一份(写时拷贝)
2.代码是逻辑,一般不可修改。数据,可读可写。进程是具有独立性的,通过数据私有,表现进程独立性。
3.父子进程fork完毕,谁先执行,不确定,这个由调度器决定。(就算在运行队列中排队也不一定,因为随时在变化)

task_struct中描述进程的属性

1.进程状态

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态,一个进程可以有几个状态

  • CPU只有一个,只有一个进程正在运行,其他进程处于什么状态呢?
  • 一个程序(或一段功能实现)需多个进程相互配合,一个进程实现完成,下一个进程继续实现需一个特殊进程实现完成后,才能运行,那他们分别处于什么状态

Linux中进程的状态会以数组的形式保留下来

static const char* const tast_state_array[]={
	"R(running)", /*0*/
	"S(sleeping)", /*1*/
	"D(disk sleep)", /*2*/
	"T(stoping)", /*4*/
	"t(tracing stop)", /*8*/
	"X(deed)", /*16*/
	"Z(zombie)", /*32*/
};
R 运行状态(running)

并不意味着进程一定在运行中,它表明进程要么在运行中,要么在运行队列里
运行状态不好查看,当我们一个进程没有输入输出,不需要I/O,将其设置为死循环,即可查看其在R状态

S 睡眠状态(sleeping)

意味着进程在等待事件完成(这里的睡眠有时候也可叫做可中断睡眠(interruptible sleep))
当事件就绪时,该S状态可被直接唤醒
可有多个进程都在等待,所以可存在等待队列

因为CPU的效率很快,我们去查看进程运行状态时多半都运行完了,此时,正在适配外设,打印到显示器。所以这时CPU处于睡眠状态,等待打印到显示器

注:
S+表示该进程此时正在前台运行(可用ctrl+c结束)
./文件名 &表示将其放在后台打印,此时状态为S。不可ctrl+c中止,只能用**kill -9 PID去结束进程

D 磁盘休眠状态(disk sleep)

有时候叫做不可中断睡眠状态(uninterruptible sleep),这个状态进程通常会等待IP的结束
通常在磁盘中使用

在这里插入图片描述
所以读取数据需要花时间,就会处于休眠等待状态
当我们OS内存紧张进程内存管理时,可能会杀掉这个IO进程,导致IO失败,这个时候我们就会把该进程设为D状态,保证进程无法被杀掉

所以S浅睡眠,可以被杀掉的,可被操作系统杀掉的
D是深睡眠,任何人都无法杀掉,除非重启或进程运行结束

T 停止状态 (stopped)

可以通过发送SIGSTOP信号来给进程来停止**(T)进程。这个被暂停的进程可以通过发送SIGCONT**信号来让进程继续

注:

kill -l可查看kill中的选项
kill -19 PID 可停止一个进程,这个时候该进程状态变为T

X 死亡状态(deed)

这个状态只是一个返回状态,你不会在任务列表里看到这个状态

Z 僵尸进程(zombie)

  • **僵尸状态(zombies)是一个比较特殊的状态,当进程退出并且父进程(使用wait()**系统调用),没有读取到子进程退出的返回代码时就会产生僵尸进程
  • 僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态码
  • 所以只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入"Z"状态
为什么会有僵尸进程?有没有什么特征?

在子进程退出时,父进程通过系统调用,OS检测进程运行完的时候,结果情况

  • 是否正常运行完
  • 是否出现异常
  • 发生了什么异常

也就是,僵尸进程的产生是保持进程退出信息,方便父进程读取获得子进程退出原因

一般,一个进程僵尸的时候,task_struct是会被保留的,进程的退出信息,是放在进程控制块中的!

也就是说,它不跑了,结束进程了,但它不会被马上free,它的信息会得到保留,这就是僵尸进程
当它被读取后,父进程知道其退出原因,就会进入死亡状态,被free掉

注:在Linux中,每一个命令都会以进程的形式去执行echo $ ?
$?最近一个命令执行的退出码,一般执行成功的退出码为0

总:
  • 僵尸进程是指先于父进程退出的子进程程序已经不再运行,但是因为保存退出原因,因此资源没有完全释放的进程,因此不会自动退出释放资源,也不会被kill命令再次杀死
  • 僵尸进程必须调用waitpid、wait接口进行等待

孤儿进程

  • 父进程如果提前退出,那么子进程后退出,称为孤儿进程
  • 孤儿进程被1号systemed进程领养,当然要有systemed进程回收

注:操作系统!=进程,操作系统是一套管理方式,只不过是1号进程帮助我们管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值