进程
程序和进程
程序就是一堆指令和数据的集合,这个集合反映在了一个静态可执行文件和相关的配置文件等。
操作系统可以运行多个程序。实际上,CPU的执行是很快的,而待运行的程序很多,那么为了让操作系统运行多个程序,CPU会把它的执行时间划分成很多段,比如每一段是0.1秒,那么就可以这样A程序运行0.1秒,然后B程序运行0.1,然后C程序运行0.2秒,因为这个切换很快,所以我们感觉程序是同时运行的。
从操作系统上来看,运行程序就指的是一个进程,因为存在切换,所以进程管理了很多资源,比如:打开的文件、挂起的信号、进程状态、内存地址空间等等,也就是说进程参与了CPU的调度,管理了所有资源。
更详细的来说,现代计算机的CPU执行速度非常快,使用一个进程参与调度时,频繁地从CPU的寄存器和进程堆栈的保存运行状态和对应的信息都很耗时,所以现代CPU将进程仅仅作为一个资源管理的东西,而引入线程作为CPU调用的基本单位,多个线程可以共享同一进程的所有资源。
要注意的是,程序并不是进程,实际上两个或多个进程不仅有可能执行同一程序,而且还有可能共享地址空间等资源。
Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息。它定义在/include/linux/sched.h中。
创建进程
fork()
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t fpid;//fpid接收fork函数返回的值
int count=0;
fpid=fork();
if (fpid < 0)
printf("error in fork!");
else if (fpid == 0) {
printf("i am the child process, my process id is %d\n",getpid());
printf("I’m children\n");
count +=2;
}
else {
printf("i am the parent process, my process id is %d/n",getpid());
printf("I’m parent.\n");
count++;
}
printf("统计结果是: %d\n",count);
return 0;
}
说明:
调用fork后,会创建一个子进程,父子进程都从fork处开始执行,fork函数有两个返回值,父进程会返回子进程的pid>0,子进程pid=0。
传统的linux操作系统以统一的方式对待所有的进程,子进程复制父进程所拥有的所有资源,这种方法使得创建进程非常慢,因为子进程需要拷贝父进程的所有的地址空间。
现代的操作系统,主要以下如下三种方式进行处理:
- 写时复制(需要不同的值)。
- 轻量级进程允许父子进程共享每进程在内核的很多数据结构,比如地址空间、打开文件表和信号处理。
- vfork系统调用创建的进程能共享其父进程的内存地址空间,为了防止父进程重写子进程需要的数据,阻塞父进程的执行,一直到子进程退出为止。
销毁进程
exit()
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t fpid;//fpid接收fork函数返回的值
int count=0;
int status = 0;
fpid=fork();
if (fpid < 0)
printf("error in fork!\n");
else if (fpid == 0) {
printf("i am the child process, my process id is %d\n",getpid());
printf("I’m children\n");
count +=2;
exit(-10);
}
else {
printf("i am the parent process, my process id is %d\n",getpid());
printf("I’m parent.\n");
count++;
}
printf("统计结果是: %d\n",count);
//父进程捕捉子进程的状态
wait(&status);
printf("parent: status: %d\n", WEXITSTATUS(status));
return 0;
}