linux内核学习(一):进程管理

参考博客: fork()函数的实现过程

http://blog.tonychow.me/blog/2013/06/27/linuxzhong-forkxi-tong-diao-yong-fen-xi/

参考书籍

《Linux内核设计与实现》

关于likely()与unlikely()函数:
转载博客

http://blog.chinaunix.net/uid-25409479-id-158584.html

likely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢?
首先明确:
if (likely(value))等价于if (value)
if (unlikely(value))等价于if (value)

也就是说likely()和unlikely()从阅读和理解的角度是一样的。
这两个宏在内核中定义如下:

define likely(x) __builtin_expect(!!(x), 1)
define unlikely(x) __builtin_expect(!!(x), 0)

这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将”分支转移”的信息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。
__buildin_expect((x), 1)表示x的值为真的可能性更大.
__buildin_expect((x), 0)表示x的值为假的可能性更大.
也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。通过这种方式,编译器在编译过程中,会将可能性更大的代
码紧跟着后面的代码,从而减少指令跳转带来的性能上的下降。
比如 :
if (likely(a>b)) {
  fun1();
}
if (unlikely(a fun2();
}
  这里就是程序员可以确定 a>b 在程序执行流程中出现的可能相比较大,因此运用了likely()告诉编译器将fun1()函数的二进制代码紧跟在前面程序的后面,这样就
cache在预取数据时就可以将fun1()函数的二进制代码拿到cache中。这样,也就添加了cache的命中率。

个人觉得重要的概念

进程:是处于执行期的程序及相关的资源的总称,是对资源调用分配的单位。程序可以有多个进程。
线程:是在进程中活动的对象!是内核调度的对象。对Linux而言,线程与进程并不特别区分,只是在调用fork()函数时,传入的参数不同,即要复制的东西不同。
Linux进程描述:Linux 中的进程描述符是一个 task_struct 类型的结构体。在 Linux 中,一个进程的进程描述符结构如下图所示:
task_struct结构,图片来自参考博客:x86体系结构对应的
task_struct 是一个相当大的数据结构,同时里面也指向了其他类型的数据结构,比如 thread_info,指向的是这个进程的线程信息; mm_struct 指向了这个进程的内存结构; file_struct 指向了这个进程打开的进程描述符结构,等等。task_struct 是一个复杂的数据结构,我们将会在下面对其进行更详细的分析。
不同架构的task_struct对应的thread_info并不同,因为有些架构的处理器中,并没有多余的寄存器用于存储这些信息,故只能在内核栈的尾端创建该结构,通过计算偏移量间接的查找.!

进程的状态:五种,进程的状态:
TASK_RUNNING: 进程是可执行的进程要么在执行,要么在运行队列中等待执行
TASK_INTERRUPTIBLE:可中断。进程正在睡眠,等待某些条件的达成。条件达成,内核就会把进程状态设置为运行。也可以接收到信号而提前被唤醒。
TASK_UNINTERUPTIBLE:不可中断。接收到信号也不会投入运行。其他和可中断相同。
__TASK_TRACED:被其他进程跟踪
__TASK_STOPPED:进程停止。进程没有投入运行,也不能投入运行。在接受到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等信号时调试期间收到这种信号,都会进入这种状态。
TASK__ZOMBIE僵尸,呆傻状态,已结束,但其父进程未接到通知,描述符未释放
TASK_SWAPPING进程页面被兑换出内存
task_struct的exit_state域中有EXIT_ZOMBIE

进程家族:所有进程都是init进程的后代,每个进程必有一个父进程。

进程的创建:调用fork()与exec()函数。

Linux的fork()采用写时拷贝页实现,写时拷贝是一种可以被推辞到甚至被免除拷贝数据的技术,内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。

fork()具体实现看参考博客

创建线程与创建进程的区别

线程的创建和普通进程创建类似,只是在调用clone()的时候,需要传递一些参数标志知名需要共享的资源。

进程的终结

进程的折构是自身引起的,该任务的大部分需要靠do_exit()执行,他需要完成的操作如下:

  1. 将标志设置为PF_EXITING
  2. 调用del_timer_sync()删除任意内核定时器。
  3. 如果BSD进程几张功能开启,do_Exit()会调用相应函数,输出记账信息。
  4. 释放mm__struct即分配的栈空间,如果资源是单独享有的话。
  5. 调用sem__exit()函数。如果进程排队等候IPC信号,它则离开队列。
  6. 退出各种资源使用
  7. 为子进程寻找养父。

    尽管调用了do_exit()后进程死了,但是进程仍旧保留了他的进程描述符,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值