进程——C

进程与程序的区别

程序:一个可执行文件,是静态的。

进程:一个正在执行的程序,是动态的。

单道和多道的区别

单道程序设计:所有进程一个一个排队等待执行。若A阻塞,则B只能等待。

多道程序设计:在计算机内存中同时存在着几道相互独立的进程,他们在管理程序控制之下,相互穿插着运行。

并行与并发的区别

并行(parallel):多核状态下,有多个指令在多个处理器下同时执行

并发:单核状态下,多个指令轮流运行,在宏观上达到并行,微观上是轮流执行

进程控制块(PCB)

进程运行时,内核为每个进程提供一个进程控制块(PCB),维护进程的相关信息,Linux内核的进程控制块是task_struct结构体

task_struct结构体

/usr/src/linux-headers-xxx/include/linux/sched.h 文件中可以查看
task_struct 结构体定义
其内部成员有很多,我们掌握以下部分即可:
进程 id:c 语言使用 pid_t 的类型表示 , 其实就是一个非负整数
进程的状态 : 有就绪、运行、挂起、停止等状态。 

PCB在内核中的存储位置

进程号

概念

每个进程都有一个进程号,类型为pid_t,进程号的范围为:0~32767。

进程号是唯一的,但是可以重复使用,当一个进程销毁时,他的进程号就可以被继续使用。

进程的编号就是该进程的进程号

内核自带两个进程,分别是进程0和进程1

进程0:调度进程,也被称为交换进程。

进程1:初始化其他进程,所以其他所有进程都是他的直接或间接子进程(后边会提)。

PID:进程号

PPID:父进程号

PGID:进程组号

获取进程id

pid_t getpid(void);

功能:获取本次进程号

返回值:本次进程号(失败返回-1)

形参:无

获取进程的父进程id

pid_t getppid(void)

功能:获取调用此函数的进程的父进程号

返回值:调用此函数的进程的父进程号

形参:无

获取进程所在进程组id

pid_t getpgrp

创建进程fork

概述

系统允许一个进程新建一个子进程,该进程为新创建的子进程的父进程

函数

pid_t fork(void)

头文件:

#include <sys/type.h>

#include <unistd.h>

失败:返回-1

成功:子进程中返回0,父进程返回子进程号

注意
foek 失败的两个主要原因是:
1 )当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为
EAGAIN
2 )系统内存不足,这时 errno 的值被设置为 ENOM
注意 :
子进程会从 fork 函数后开始执行

示例

父子进程关系

使用fork函数得到的子进程其实就是父进程的一个复制品,他从父进程处复制了地址空间 (包括进程上下文、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等 ),子进程独有的只有他的进程号,计时器等。

因此,使用fork的代价是非常大的(但是还是得用)

示例2

代码1

运行结果

代码2

运行结果

分析

代码1和代码2的区别只有第6行的printf中多了一个\n

打印出来的内容却不一样

printf在打印内存时,会将打印的数据存放在缓冲区

代码1使用了换行缓冲,所以此时的缓冲区中没有内容

而代码2中第6行中的printf中的内容还停留在缓冲区

创建子进程时,子进程会拷贝父进程缓冲区的内容,因此也会打印Hello

思考

该程序运行结果是?

答案:HelloWorldHello

进程状态

分类

进程状态可以分为三大状态和五大状态

三大状态

        运行态,就绪态,阻塞态

五大状态

        创建态,运行态,就绪态,阻塞态,终止态

ps查看进程状态

进程资源的回收

概述

回收原则:谁创建谁回收

在每个进程结束的时候,内核释放该进程的所有资源,但仍为其保留一些信息,主要是PCB信息(包括进程号、退出状态、运行时间等)

wait函数

头文件

#include <sys/type.h>

#include <sys/wait.h>

函数

pid_t wait(int *status)

参数:status(进程退出时的状态信息)

返回值:pid_t(成功:已经结束子进程的进程号;失败:-1)

注意:

        因为回收原则,所以必须在父进程中调用

        会阻塞当前进程,知道回收一个子进程

示例

运行结果

exit函数与_exit函数

exit

头文件 

        exit是一个库函数

        #include <stdio.h> 

函数

        void exit(int status);

_exit

头文件

        #include <unistd.h>

函数

        void _exit(int status);

区别

_exit是系统调用函数
而exit的底层是_exit函数,所以相对而言exit效率低

示例

运行结果

WIFEXITED与WEXITSTATUS

WIFEXITED

判断进程是否正常退出,如果子进程是正常终止的,取出的值非0

WEXITSTATUS

返回子进程的退出状态值(保存在status变量的8-16位)

waitpid函数

#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
功能 :
等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。
参数:
pid : 参数 pid 的值有以下几种类型:
pid > 0 等待进程 ID 等于 pid 的子进程。
pid = 0 等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程
组, waitpid 不会等待它。
pid = -1 等待任一子进程,此时 waitpid wait 作用一样。
pid < -1 等待指定进程组中的任何子进程,这个进程组的 ID 等于 pid
绝对值。
status : 进程退出时的状态信息。和 wait() 用法一样。
options : options 提供了一些额外的选项来控制 waitpid()
0 :同 wait() ,阻塞父进程,等待子进程退出。
WNOHANG :没有任何已经结束的子进程,则立即返回。(非阻塞)
WUNTRACED :如果子进程暂停了则此函数马上返回,并且不予以理会子进程的
结束状态。(由于涉及到一些跟踪调试方面的知识,加之极少用到)
返回值:
1) 当正常返回的时候, waitpid() 返回收集到的已经回收子进程的进程号; 2) 如果设置了选项 WNOHANG ,而调用中 waitpid() 还有子进程在运行 , 且没有子
进程退出,返回 0, 父进程的所有子进程都已经退出了返回 -1 ; 返回 >0 表示等到一个子
进程退出;(重要)
3) 如果调用中出错,则返回 -1 ,这时 errno 会被设置成相应的值以指示错误所
在,
: pid 所对应的子进程不存在 , 或此进程存在 , 但不是调用进程的子进程 ,waitpid()
就会出错返回 , 这时 errno 被设置为 ECHILD

atexit函数

作用

进程在退出之前可以用atexit函数注册退出处理函数

注意

1.一个进程至多可以注册32个函数,由exit调用

2.以与等级相反的顺序调用

特殊进程

僵尸进程

        子进程已经结束,父进程没有回收子进程资源(有危害:子进程的pid被占用,系统的pid数量是有限的)

孤儿进程

        父进程比子进程先结束(无危害:子进程被1号进程接管)

守护进程

        又名精灵进程、不死进程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值