1. Linux中的进程和线程 ·进程 进程是出于执行期的程序以及它所包含的资源的总称。它有4个要素: 一段可执行的程序; 进程专用的系统堆栈空间; 内核中有一个task_struct数据结构; 有独立的存储空间,意味着拥专有的用户空间; ·线程 如果进程缺少第4个条件,则称为线程。 完全没有用户空间,称为内核线程;如果共享用户空间,称为用户线程。 对Linux来说,线程只是一种进程间共享资源的手段。 注意:此处的线程 与 系统中在用户空间的同一内实现的线程 的区别?(4要素) Linux系统中,进程在诞生之初都与父进程共用一个存储空间,严格说此时还是线程;当其建立自己的存储空间,并与父进程分道扬镳后,成为真正意义上的进程。 Linux系统中进程process和任务task是同一个意思。 2. 进程描述符 process descriptor 在<linux/sched.h>中定义的task_struct。 Linux通过slab分配器分配task_struct,所以只需在系统堆栈栈底创建一个新结构thread_info,该结构中的task域存放指向该任务的task_struct指针。(参见:http://feizf.blogbus.com/logs/16835565.html) 内核通过PID来标识每个进程,PID存放在各自的进程描述符中。 内核中通过current宏查找当前正在运行进程描述符,该宏的实现与硬件体系结构相关。 3. 进程状态 每个进程必然处在5种状态之一,如下图所示: task_running表示一个进程正在执行; task_interruptible和task_uninterruptible均表示进程出于睡眠状态。(这里的中断是指睡眠能否因其它事件而中断) uninterruptible表示出于深度睡眠而不受信号的打扰。sleep_on( )和wake_up( )用于深度睡眠,interruptible_sleep_on( )和interruptible_wake_up( ); task_zombie(僵死)表示进程已经结束,只是父进程还没有调用wait4( )系统调用; task_stopped表示进程停止执行,主要用于调试; 4. 进程上下文的理解 程序在用户空间执行时,当调用了系统调用或者触发异常,就会陷入内核空间。此时称内核“代表进程执行”并处于进程上下文中。所以此时current宏是有效的。 与中断上下文的区别:中断时,系统不代表进程执行,而是执行一个中断处理程序。 5. 进程间的关联方式 1) 进程家族树 所有进程都是PID为1的init进程的后代。 2) Hash表为基础的进程队列的阵列 对pid进行hash计算,以计算结果为下标在hash表中找到一个队列。 3) 线性队列; Init_task为头结点,后面创建的进程通过其task_struct结构中的next_task和prev_task两个指针链入这个线性队列。 这3个队列都是静态的,每个进程必同时处于3个队列之中。 在运行的过程中,进程可以动态的链接进可执行队列接受系统的调度。 6. 进程创建 Linux通过fork()和exec()两个函数完成进程的创建。 fork()通过拷贝当前进程创建一个子进程。子进程有自己 的task_struck结构和系统空间堆栈,但与父进程共享其它所有资源。fork()使用写时拷贝copy-on-write页实现。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。 exec()负责读取可执行文件并将其载入地址空间开始运行。 创建子进程后,父进程有3个选择: if(!child=fork()) //创建子进程 6. 进程终结 当一个进程终结时,内核会释放它所占有的资源,并把这一消息告知父进程。 参考书籍:《Linux内核设计与实现》、《Linux内核源代码分析》 |