第3章--进程管理

第3章--进程管理


3.1 进程与线程

    进程是处于执行期的程序,但是进程不仅仅局限于一段可执行程序代码(代码段),还包括与之相关的资源。线程是在进程中活动的对象,内核调度的对象是线程而不是进程,Linux中,线程被当成一种特殊的进程来处理,处理的方式为:Linux创建多个进程并分配普通的task_struct结构,并指定他们共享某些资源(线程共享进程的资源)。


3.2 进程描述符的分配及存放

    内核把进程的列表存放在叫做任务队列(task_list)的双向循环链表之中,链表中的每一项都是进程的描述符(task_struct结构),用来描述进程的所有信息。Linux通过slab分配器分配task_struct结构,可以通过内核栈的地址(x86的esp寄存器存放了栈地址)计算出task_struct结构的首地址。在Linux 2.6内核以前,将task_struct结构放在内核栈的底部(不是栈底)(低地址,小端模式)(显然会大幅占用栈空间,如果栈溢出将task_struct的空间冲掉会有很大的危险),将esp的低13位屏蔽掉的结果就是当前进程的task_struct结构的首地址,Linux 2.6之后,栈的底部存放的是thread_struct的结构,这个结构内的*task指针会指向当前的task_struct结构的首地址,这种方法不仅可以找到当前进程的描述符,还可以减少对栈空间的占用。不过,PowerPC体系结构的处理器并不需要通过堆栈寄存器来得到task_struct,与x86不同,PowerPC有着足够的寄存器,可以将当前进程的进程描述符存放在一个专用的寄存器之中以方便使用。


3.3 进程的状态与切换

    进程的状态一般分为五种,由进程描述符的state域进行描述,分别为:

    • TASK_RUNNING(运行)---进程是执行的;它或者正在执行,或者在运行队列之中等待执行(即三元态进程所指的运行态和就绪态)。
    • TASK_INTERRUPTIBLE(可中断)---进程正在睡眠(也就是被阻塞),等待某些条件的达成。一旦这些条件达成,内核就会把进程状态设置成运行。处于此状态的进程也会因为接收到信号而提前被唤醒并随时准备投入运行。
    • TASK_UNINTERRUPTIBLE(不可中断)---与可中断的状态不同在于,就算是接收到信号也不会被打断并投入运行(也相当于阻塞态)。这个状态一般在进程必须在等待时不受干扰或者等待事件很快就会发生时出现。
    • __TASK_TRACED---被其他进程跟踪的进程。
    • __TASK_STOPPED(停止)---进程停止执行;进程没有投入运行也不能投入运行,这种状态发生在接收到SIGSTOP、SIGTSTP等状态时出现。

    进程的状态可以使用set_task_state(task,state)来进行设置。


    3.4 进程创建

    Linux中使用fork()实现进程的创建,并使用exec()函数族来读取进程的可执行文本并将其载入到地址空间运行。需要注意的是,fork()函数使用了写时拷贝(copy-on-write)技术,当调用完fork()函数时,并不会立即将父进程的数据copy到子进程,而是让子进程以只读的方式共享父进程的copy,只有需要在写入时(无论是父子进程数据),才会发生copy的操作。Linux在fork()之后分别在父子进程中返回一次,并有意让子进程先运行(并不一定能如愿),因为很多子进程在调用完fork()函数之后紧接着会执行exec()函数族。

原文地址:https://www.cnblogs.com/blackeyes/p/6158428.html