Linux学习之进程

一、      进程与线程

进程就是处于执行期的程序,但进程并不仅仅局限于一段可执行代码。通常进程还包含其他资源,像打开的文件、挂起的信号、一个或者多个具有内存映射的内存地址空间及一个或多个线程等。进程拥有独立的虚拟处理器和虚拟内存。

  线程就是在进程中活动的对象,每个线程都拥有一个独立的程序计数器、线程栈和一组进程寄存器,线程拥有独立的虚拟处理器。

  Linux内核调度的是线程而不是进程,线程是特殊的进程。

二、      进程描述符以及任务结构

      内核把进程的列表存放在任务队列的双向循环链表中,链表中的每一项都是类型为task_struct的进程描述符结构体,存储于内核栈顶。在32位机器上大约有1.7K。每个进程拥有独立的内核栈,32位的CPU只有8K的内核栈,所以在写程序的时候要注意使用的栈不要超过了7K。

Structtask_struct  {}结构体如下:


进程描述符分配:

       当进程由于终端或者系统调用从用户空间状态转换到内核态时,进程所用的栈也从用户栈切换到内核栈。

        通过用slab分配器动态生成task_struct,所以只需要在栈底(对于向下增长的栈来说)或栈顶(对于向上增长的栈来说)创建一个新的结构体structthread_info。

structthread_info {}结构体如下:


structthread_info {}结构体里面的structtask_struct *task指向进程描述符的结构体(在X86上面是这么实现的,由于寄存器资源不够,在有些专用处理器比如PPC上是保持在寄存器里面的)。


使用slab分配器的好处:其实slab分配器是初始化好了的一片内存,需要的时候直接拿来使用,使用完后直接放回去。这样就防止了使用伙伴系统在平凡分配内存的时候造成内存碎片。

       通过thread_info的地址就可以找到task_struct地址;在不同的体系结构上计算thread_info的偏移地址不同。

/*linux-2.6.38.8/arch/arm/include/asm/current.h */

staticinline struct task_struct *get_current(void)

{

    return current_thread_info()->task;

}

#definecurrent (get_current())

/*linux-2.6.38.8/arch/arm/include/asm/thread_info.h */ 

staticinline struct thread_info *current_thread_info(void)

{

   //栈指针

    register unsigned long sp asm("sp");

    return (struct thread_info *)(sp &~(THREAD_SIZE - 1));

}

三、进程状态:


系统中的每个进程都必然处于以上所列进程状态中的一种。

   TASK_RUNNING表示进程要么正在执行,要么正要准备执行。

   TASK_INTERRUPTIBLE表示进程被阻塞(睡眠),直到某个条件变为真。条件一旦达成,进程的状态就被设置为TASK_RUNNING,处于此状态的进程也会因为接收到信号而提前被唤醒并且随时准备投入运行。

   TASK_UNINTERRUPTIBLE的意义与TASK_INTERRUPTIBLE类似,除了不能通过接受一个信号来唤醒以外。

__TASK_STOPPED表示进程被停止执行,通常这种状态发生在接收到SIGSTOP

SIGTSTPSIGTTINSIGTTOU等信号的时候,此外在调试期间接收到的任何信号都会进入这种状态。

   __TASK_TRACED表示进程被debugger等进程监视,例如使用ptrace对调试程序进行跟踪。

   EXIT_ZOMBIE表示进程的执行被终止,但是其父进程还没有使用wait()等系统调用来获知它的终止信息。

   EXIT_DEAD表示进程的最终状态。

    EXIT_ZOMBIE EXIT_DEAD 也可以存放在 exit_state 成员中。进程状态的切换过程和原因大致如下图(图片来自《 Linux Kernel Development 》):


四、设置进程状态:

Set_task_state(task,state);           /*将任务task的状态设置为 state*/

Set_task_state(current,state);  和set_current_state(state)的功能是一样的。

五、Linux线程:

Linux线程其实就是一种特殊的进程,也是通过进程进行调度、有相同的进程描述符等。不同的是在同一个进程下的线程组共享内存地址、文件资源等。而进程之间的内存地址是独立的。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间(实际上指向地址空间的mm指针被设置为NULL)。它们只在内核空间运行,从来不会切换到用户空间去。内核线程和普通进程一样,可以被调度,可以被抢占。

六、孤儿进程的处理:

如果父进程在子进程之前退出,必须有机制保证子进程能找到一个新的父亲,否则这些成为孤儿的进程会在退出时永远处于僵尸状态,白白地耗费内存。解决方法是给子进程在当前线程组内找一个线程作为父亲,如果不行,就让init做他们的父亲。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值