一:进程
(1)简介
进程就是处于执行期的程序,但是进程并不仅仅限于一段可执行程序代码,通常进程还要包含其他资源,像打开的文件,挂起的信号,内核内部数据,处理器状态,一个或者多个具有内存映射的内存地址空间及一个或多个执行线程,当然还包括用来存放全局变量的数据段等。实际上进程就是正在执行的程序代码的实时结果。在现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存。虽然实际上可能是许多进程正在分享一个处理器,但是虚拟处理器给进程一种假象,让这些进程觉得自己在独享处理器。而虚拟内存让进程在分配和管理内存的时候觉得自己可以拥有整个系统的所有内存资源。比较有趣的是在同一个进程的多个线程之间可以共享虚拟内存,但是每个都拥有各自的虚拟处理器。
进程 = 执行的程序 + 资源 进程的另外一个名字是任务(task)
fork函数将运行着的程序分成2个(几乎)完全一样的进程,
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t fpid;
int count = 0;
fpid = fork();//fork返回两次 一次返回给父进程 一次返回给子进程
//子进程也是从这个地方开始执行的 因为他拷贝了父进程的信息
if(fpid < 0)
{
printf("error in fork!\r\n");
}
else if(fpid == 0)//子进程
{
printf("I am the child process ,my process id is %d\r\n",getpid())
count++;
}
else
{
printf("父进程id:%d\r\n",getpid());
count++;
}
printf("count=%d\r\n",count);
return 0;
}
在语句fpid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的几乎完全相同,将要执行的下一条语句都是if(fpid<0)
为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;
在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。fork执行完毕后,出现两个进程,进程1的变量为count=0,fpid!=0(父进程)。进程2的变量为count=0,fpid=0(子进程),这两个进程的变量都是独立的,存在不同的地址中,不是共用的,这点要注意。可以说,我们就是通过fpid来识别和操作父子进程的。还有人可能疑惑为什么不是从#include处开始复制代码的,这是因为fork是把进程当前的情况拷贝一份,执行fork时,进程已经执行完了int count=0;fork只拷贝下一个要执行的代码到新的进程就行,之前执行完的信息和内容都已经拷贝过去了。在进程描述符中有一个很重要的内容就是PID,PID是一个数,通过这个数唯一标识这个进程。
(2)加深
进程描述符(task_struct)是用来描述一个进程的所有信息的结构体,内核把很多个进程描述符存放在叫做任务队列的双向循环链表中。现在的linux内核通过slab分配器来动态生成task_struct。
二:线程
执行线程,简称线程(thread),是在进程中活动的对象。每个线程都拥有一个独立的程序计数器、进程栈和与一组进程寄存器。内核的调度单位是线程而不是进程。在现在的操作系统中一个进程可以包含多个线程。对于Linux来说,进程和线程并不特别区分,线程只不过是一种特殊的进程罢了。
在Linux中实现线程的机制非常独特。从内核角度来说,它并没有线程这个概念。Linux把所有的线程都当成进程来实现。内核没有准备特别的调度算法或者是定义特别的数据结构来表征线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。而对于Windows或者是Sun Solaris等操作系统,线程和进程是相差特别大的,线程被抽象成一种耗费较少资源,运行迅速的执行单元。而对于Linux来说,它只是一种进程间共享资源的手段(Linux的进程本身就够轻量级了)。
线程的创建和普通进程的创建类似,只不过在调用clone()的时候需要传递一些参数标志来指明需要共享的资源。子线程和父进程共享地址空间,文件系统资源,文件描述符和信号处理程序。