Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103097
  • 博文数量: 30
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 402
  • 用 户 组: 普通用户
  • 注册时间: 2014-07-22 11:09
个人简介

摸着石头过河

文章分类

全部博文(30)

文章存档

2015年(2)

2014年(28)

我的朋友

分类: LINUX

2014-11-20 14:57:34

        作为一名菜鸟学习Linux内核网络模块,打算先看这本《Linux内核设计与实现》再看《深入理解Linux网络技术内幕》。
现把所学历程记录成笔记以激励自己坚持学习。
        1、基本概念
             同一个进程中的线程共享该进程的虚拟内存(也就是进程的地址空间),但是独享虚拟处理器。进程的创建通过系统调用fork(),该函数返回两次,一次返回到新创建的子进程中,另一次返回到父进程中。因此可能存在主进程调用fork时尚未返回子进程已经开始运行了。子进程退出时被设为僵死状态,直到父进程调用wait()函数。
      2、进程描述符及任务结构
           进程用struct task_struct 来表示,也叫做进程描述符(对进程的描述,自然要包含进程的所有信息)。2.6版本以前进程描述符存储在自己的内核栈的栈尾,2.6以后Linux使用slab分配器来为进程描述符分配内存空间,通过双向链表来组织进程描述符。这个样每个进程的task_struct 就存储在双向链表里面了。然后在进程内核栈的尾端存储一个 struct thread_info,struct thread_info中有一个指针变量 struct task_struct *task 指向进程描述符 。 内核通过宏current来找到当前正在执行进程的进程描述符。在x86体系结构中current会从thread_info中通过task指针找到正在运行的进程描述符。
           进程通过PID来唯一标示一个进程,该字段是struct task_struct的一个域。
      3、进程的状态
         (1)TASK_RUNING
                  运行,表示进程可以运行,当前进程可能是正在运行也有可能是在就绪队列中。
         (2)TASK_INTERRUPPIBLE
                  可中断,表示进程正在被阻塞,等待条件的发生。当条件发生时,或者被信号唤醒。进程就进入运行态。
         (3)TASK_UNINTERRUPPIBLE
                  不可中断,该进程也是处于阻塞,但是不能被信号唤醒,只能是被等待的条件发生才能唤醒。
         (4)TASK_ZOMBLE
                 僵死,处于该状态的进程也叫做僵尸进程,进程已经运行结束了,但是其父进程还没有调用wait(),为了使父进程可以 获知其状态信息,该进程的进程描述符并没有释放。
         (5)TASK_STOPPED
                  停止,进程已经停止运行。一般是收到信号SIGSTOP等。
           内核对进程状态的设置调用函数set_task_state(task,state)
        4、进程家族
             进程描述符中有个指针struct task_struct *parent  指向该进程的父进程,指针struct task_struct*children指向该进程的子进程链表。
       5、进程的创建
            进程创建在用户层调用系统接口fork()-----》调用clone()-----》调用do_fork()------>调用copy_pocess()
             在fork中调用clone时传递的参数是clone(CLONE_SIGCHLD,0)
            
        6、线程的实现
             在linux内核中其实并没有线程,线程就是进程,线程的数据结构就是struct task_struct,这与windows系统是有区别的,windows内核中有专门的   线程数据结构。我们知道进程间的地址空间是独立的,而线程间的地址空间是共享的,因此linux下,两个进程公用一个进程地址空间就行形成了多线程。
          
 在线程中调用clone(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGCHLD,0)
        7、进程的退出
            每个进程最终都会终结的,在用户态进程的退出是通过调用exit或者从main函数return,实际上编译器在编译c的main函数时会在后面加上exit函数
        ,exit调用do_exit,do_exit的功能实现进程终结前的一些清理工作,比如调用exit_notify()向父进程发送信号然后处于TASK_ZOMBLE状态就不能运行了,在最后阶段会调用schedule切换到其他进程执行。到此时进程的struct_task、thread_info和内核栈资源还是存在的。
           父进程调用wait(),获取其退出的子进程的状态,并释放子进程的剩下的那三个资源。也就是说如果父进程不调用wait那么子进程就会一直处于TASK_ZOMBLE状态。
            有一种情况是父进程先于子进程退出,那么就得为这个子进程重新找一个父进程,否则这个子进程退出后就会一直出去TASK_ZOMBLE状态,那么它占用的内存资源不会得到释放。同时也说明了,父进程中必须要调用wait函数来处理子进程的退出问题,否则就会浪费内存资源,而调用wait时如果当前进程没有子进程退出就会阻塞当前进程,因此可以采用signal函数,当接收到子进程的退出时发送的信号时signal的处理函数调用wait,这样子进程占用的内存资源就会释放了。
            系统会为失去父进程的子进程寻找父进程,如果一个父进程当初创建了多个子进程,那么就会在这些子进程中间寻找一个子进程当做新的父进程,如果只有一个子进程就会让init进程做父进程。
           

           

阅读(653) | 评论(0) | 转发(0) |
0

上一篇:linux进程间通信

下一篇:Python学习要点

给主人留下些什么吧!~~