进程:
进行就是正在进行中的程序,程序运行起来需要被加载到内存中。进程就是操作系统的描述,这个描述叫PCB(进程控制块),Linux下PCB有自己的名字叫task_struct。而操作系统就是使用task_struct结构体描述进程,使用双向链表来将这些结构体组织起来进行管理。
task_struct(PCB)内容分类:
标识符:就是进程的PID。
状态:任务状态、退出代码,退出信号等。
优先级:相对于其他进程的优先级。
程序计数器:程序中即将被执行的下一条指令的地址。
内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
上下文数据:进程执行时处理器的寄存器中的数据。
I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
每个进程都会有一个非负整数的表示的唯一进程ID,因为进程标识符总是唯一的,但进程ID是可复用的,当一个进程终止后,其进程ID就会成为复用的候选者,但系统会实现延迟复用算法,使得新进程的ID不同于最近终止进程所使用的ID。
那么,到底什么是进程呢?又为什么要有进程?
CPU一次只能处理一个程序,CPU速度很快,而内存很慢,所以CPU会有大量的时间都是空闲的。而CPU又是很昂贵的,为了解决浪费CPU的情况,就出现了中断处理,将程序分成一小片一小片的,这个进程执行一点,那个进程执行一点。虽然在内部进程的执行是一段一段的,但是CPU的速度很快的(速度都是纳秒级别的),所以我们是感受不到进程执行过程中的停顿的。
查看进程信息的命令
ps -ef:查看所有的进程信息。
ps aux:查看进程的详细信息。
top;(查看进程的信息)
查看你所要的进程信息: ps -ef | 名字。
getpid();(在代码中获取一个进程的id)(一个系统的调用接口)
#include<stdio.h>
int main()
{
printf("%d\n", getpid());//使用getpid()来获取一个进程的id
return 0;
}
创建新进程
一个现有的进程可以调用fork函数创建新进程。
#include<unistd.h>
pid_t fork(void);
//子进程返回0,父进程返回子进程ID
由fork创建的新进程被称为子进程。fork函数被调用一次,就会返回两次。子进程返回0,父进程返回子进程ID。将子进程ID返回给父进程的理由是:因为一个进程的子进程有多个,并且没有一个函数使一个进程可以获得所有子进程的进程ID。 因为子进程是根据父进程为模板来创建的,因此父子的代码段是一样的(父子进程运行的是同一段代码)。但是父子进程的返回值不同。父子进程的数据不相同。子进程的数据会另外开辟内存来存放。对于代码来说父子进程是相同的(相同的代码只是fork()之下的代码,而不是从头到尾),但是父子进程的数据是独有的(写时复制技术)。
父进程是从代码头到代码的结束。子进程是从fork()开始到代码结束。
进程的状态
R(running) 运行态:并不意味着程序一定在运行中,它表明进程要么在运行中要么在运行队列里。
S(sleeping) 可中断的休眠(浅度睡眠)
D(disk sleep) 不可被中断的休眠,只能通过指定的方式--->唤醒(深度睡眠)
T(stopped) 停止的状态
t(tracing stop) 追踪状态
X(dead) 死亡状态
Z(zombie) 僵死态