为什么要学习进程?
我们现在的很多程序,在执行的过程中,需要同时处理多个任务,因此我们需要学习多进程或多线程来实现多任务处理的需要,可以提高我们程序的执行效率
进程的概念
一个正在运行的程序以及它所依赖的资源的总称,进程也是系统进行资源分配的基本单位,也是线程的容器
进程与线程
进程是程序的执行过程,程序是进程的执行文本,一个进程只能对应一个程序,一个程序可以对应多个进程
查看进程
Windows:任务管理器
Linux:top(动态查看有哪些进程),ps
杀死进程:kill + pid
进程标识符pid
在某个时刻,计算机中运行了多个程序,这些程序对于内核来说,如何进行调度,如何进行管理,因此,系统给每个正在运行的程序都分配了一个大于等于0的正整数的编号,这个编号就是我们的进程标识符
在计算机中,系统一旦被运行,默认就会创建三个特殊的进程 0,1,2
进程pid的编号一般是0-32767
程序是如何转换成进程?
程序需要从硬件加载到内存,在加载的同时系统会为该程序在内存中划分内存四区
内核会为该程序构建一个内存块(结构体),来描述该进程的相关信息(内核需要登记运行程序的相关信息),将该进程加入就绪队列
进程控制块PCB
为了更好的对每个进程做描述它的本质是一个结构图 size>=1KB
进程的状态
就绪,停止,阻塞
就绪:
进程已经获取到除处理器外的所有资源,等待分配处理器资源,只要分配到处理器资源就可以运⾏。⼀般就绪进程是会有⼀个就绪进程队列,有系统来调度。
运⾏:
进程正在执⾏。
进程阻塞:
进程因等待某个事件发⽣⽽暂停运⾏。
停⽌ (stop) :
进程已经完成任务。

进程的状态转化:
运⾏----> 就绪 正在运⾏的进程因时间⽚到,转⼊就绪队列等待重新调度。
就绪--->运⾏ 系统进⾏进程调度,拿出就绪队列中的某个进程运⾏。
运⾏----> 等待 正在运⾏的进程因等待某事件发⽣,转⼊等待状态。
等待--->就绪 处于等待状态的进程,因所等待的事件发⽣了,进⼊就绪对队列让系统调度运⾏。
进程的特点
(1)动态性:进程的实质是程序的⼀次执⾏过程,进程是动态产⽣,动态消亡的。
(2)并发性:任何进程都可以同其他进程⼀起并发执⾏。
(3)独⽴性:进程是⼀个能独⽴运⾏的基本单位,同时也是系统分配资源的独⽴单位;
(4)异步性:由于进程间的相互制约,使进程具有执⾏的间断性,即进程按各⾃独⽴的、不可预知的速度向前推进。
进程的分类
在Linux操作系统中,进程⼤致可以分为3中不同的类型,每种进程都有⾃⼰的特点和属性。
交互进程:也称为终端进程,由⼀个Shell启动的进程,交互进程既可以在前台运⾏,也可以在后台运⾏。
批处理进程:这种进程和终端没有联系,即执⾏的是批处理⽂件、shell脚本。
监控进程:也称守护进程(daemon)是⼀类在后台运⾏的特殊进程,⽤于执⾏特定的系统任务。守护进程⼀般在系统启动时开始运⾏,除⾮强⾏终⽌,否则直到系统关机都保持运⾏。
进程的创建
创建进程有两种⽅式:1)操作系统创建 2)⽗进程创建。
进程的创建可以通过system函数、exec系列函数(execl、execlp等)、fork函数实现。
system函数
函数原型为: int system(const char*filename)
使⽤时需要包含头⽂件: stdlib.h
主要⽤于执⾏shell命令。
功能为:建⽴独⽴进程,拥有独⽴的代码空间,内存空间,等待新的进程执⾏完毕,system才返回.(阻塞),system函数其实内部会调⽤fork函数来产⽣⼦进程。
复制进程fork函数
函数原型为: pid_t fork(void)
功能:fork 函数会新⽣成⼀个进程,调⽤ fork 函数的进程为⽗进程,新⽣成的进程为⼦进程。⼦进程复制了⽗进程打开的⽂件描述符。
函数返回值:函数返回类型 pid_t 实质是 int 类型,Linux 内核 2.4.0 版本的定义是:
在⽗进程中返回⼦进程的 pid,在⼦进程中返回 0,失败返回-1。
所属头⽂件:unistd.h
上述代码总结:
fork函数被⽗进程调⽤⼀次,但是却返回两次;⼀次是返回到⽗进程(⼦进程id),⼀次是返回到新创建的⼦进程(是0)。
被fork的⼦进程会和和它⽗进程⼀样,继续执⾏当前的程序。

fork()函数出错可能有两种原因:
1、当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN
2、系统内存不⾜,这时errno的值被设置为ENOMEM
练习
利用多进程,设计一个程序实现交替打印ping和pong字符串
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
int i = 0;
for(;i<3;i++)
{
fork();
printf("pin \n");
printf("pong \n");
}
}
设计程序创建三个子进程实现一个打印"###",一个打印"$$$",另外一个打印"***"
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t a,b,c;
a = fork();
printf("###\n");
if (a <= 0)
exit (0);
b = fork();
printf("$$$\n");
if (b <= 0)
exit (0);
c = fork();
printf("***\n");
if (c <= 0)
exit (0);
}
设计一个程序,检测一个数组中的数据是否全是连续的,比如{7,8,9,10}就是连续的,{3,5,8,9}就不是
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void fun(int **a,int n)
{ int i = 0;
int b = 0;
for(;i<n - 1;i++)
{
if(*a[i]+1 == *a[i+1])
b++;
}
if(b == 3)
printf("他是连续的数据\n");
else
printf("不是连续的数据\n");
}
int main()
{
int a = 7,b = 8,c = 9, d = 10,a1 = 3,b1 = 5,c1 = 8,d1 = 9;
int *arr1[] = {&a,&b,&c,&d};
int *arr2[] = {&a1,&b1,&c1,&d1};
fun(arr1,4);
fun(arr2,4);
return 0;
}