旅游论坛网站建设,合作公司做网站,网站设计怎么自学,分类目录网站怎么做2. 进程管理
2.1 Linux进程
进程是程序执行时的一个动态实体#xff0c;包含程序计数器、全部CPU 寄存器的值和进程堆栈中存储着的一些临时数据#xff0c;如子程序参数、返回地址及变量等#xff0c;反映的是当前处理器的活动状态。 而程序是仅包含指令和数据的一段静态代…2. 进程管理
2.1 Linux进程
进程是程序执行时的一个动态实体包含程序计数器、全部CPU 寄存器的值和进程堆栈中存储着的一些临时数据如子程序参数、返回地址及变量等反映的是当前处理器的活动状态。 而程序是仅包含指令和数据的一段静态代码。Linux 是一个多处理操作系统进程拥有独立的权限和单一职责每个进程都运行在各自独立的虚拟地址空间中只有通过内核控制下的进程通信机制管道、信号、信号量、消息队列等它们之间才能发生通信。从内核的观点看 进程的目的就是担当分配系统资源CPU 时间、内存等的实体。 进程管理的最终目的就是在各进程顺畅执行的条件下合理分配系统资源给不同的进程。子进程刚被创建时是父进程地址空间的一个逻辑备份与父子进程共享程序代码但它们分别拥有独立的数据备份。因此子进程对堆和栈中的数据进行修改时对父进程的数据是不会有影响的。
2.2 进程描述符 内核对进程的优先级、进程的状态、地址空间等采用进程描述符表示。在 Linux 内核中进程用一个相当大的称为 task_struct 的结构表示。下面是从 linux-2.6.29\include\linux\sched.h 中摘抄出来的进程描述的部分信息 struct task_struct {volatile long state; /* 进程状态 -1不能运行 0运行 0停止 */void *stack;atomic_t usage;unsigned int flags; /* 指示符进程创建PF_STARTING退出PF_EXITING在分配内存PF_MEMALLOC */unsigned int ptrace;int lock_depth; /* BKL lock depth *//* 每个进程都会被赋予优先级称为 static_prio但实际优先级是基于多因素动态决定的值越低优先级越高。 */int prio, static_prio, normal_prio;unsigned int rt_priority;const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt;unsigned char fpu_counter;s8 oomkilladj; /* OOM kill score adjustment (bit shift). */unsigned int policy;cpumask_t cpus_allowed;struct list_head tasks; /* 提供链接能力,包含prev指针指向前一个任务,next指针指向下一个任务 *//* 进程地址空间由mm和active_mm表示,mm代表进程内存描述符active_mm代表前一进程内存描述符为改进上下文切换时间的一种优化 */struct mm_struct *mm, *active_mm;/* task state */struct linux_binfmt *binfmt;int exit_state;int exit_code, exit_signal;int pdeath_signal; /* The signal sent when the parent dies */unsigned int personality;unsigned did_exec:1;pid_t pid;pid_t tgid;struct task_struct *real_parent; /* real parent process */struct task_struct *parent; /* recipient of SIGCHLD, wait4() reports */struct list_head children; /* list of my children */struct list_head sibling; /* linkage in my parents children list */struct task_struct *group_leader; /* threadgroup leader */struct list_head ptraced;struct list_head ptrace_entry;struct pid_link pids[PIDTYPE_MAX];struct list_head thread_group;struct completion *vfork_done; /* for vfork() */int __user *set_child_tid; /* CLONE_CHILD_SETTID */int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */...
};2.3 进程状态
进程描述符中 state 字段描述进程当前的状态。它由一组标志组成其中每个标志描述一种可能的进程状态。在 2.6 内核中进程只能处于这些状态中的一种。下面分别对这些状态进行描述。 可运行状态TASK_RUNNING进程处于运行系统当前进程或者准备运行状态等待系统将 CPU 分配给它。等待状态WAITING进程在等待一个事件或者资源。 Linux 将等待进程分成两类可中断的等待状态 TASK_TNTERRUPTIBLE与不可中断的等待状态(TASK_UNINTERRUPTIBLE。前者可被信号中断后者直接在硬件条件等待并且任何情况下都不可中断。暂停状态TASK_STOPPED 进程被暂停 通常是通过接收一个信号SIGSTOP、SIGTSTP、 SIGTTIN 或 SIGTTOU转为暂停状态。正在被调试的进程可能处于停止状态。僵死状态EXIT_ZOMBIE 进程的执行被终止 但其父进程还没有执行wait4()或 waitpid()系统调用返回有关该死亡进程的信息。
2.4 进程调度
Linux 进程调度指的是在所有可运行状态的进程中选择最值得运行的。每个进程的 task_struct 结构中的 policy、 priority、 counter 和rt_priority 这 4 项是选择进程的依据。 policy 进程调度策略用于区分普通进程和实时进程实时进程优先于普通进程运行priority 进程包括实时和普通的静态优先级counter进程剩余时间片起始值就是 priority 的值因为 counter 用于计算一个处于可运行状态的进程值得运行的程度 goodness所以 counter 也被看做是进程的动态优先级。rt_priority实时进程特有的优先级别用于实时进程间的选择。 Linux进程分类 Linux 在执行进程调度的时候对不同类型的进程采取的策略也不同一般将 Linux 分为以下 3 类 交互式进程当有用户输入时这类进程必须很快地激活。通常要求延迟在 50150 毫秒。典型的交互式进程有控制台命令、文本编辑器、图形应用程序等。批处理进程Batch Process这类进程一般在后台运行所以不需要非常快地反应经常被调度期限制。典型的批处理进程有编译器、数据库搜索引擎和科学计算等。实时进程这类进程对调度时间有非常严格的要求不能被低优先级进程阻塞在很短时间内需做出反应。典型的实时进程有音视频应用程序、机器人控制等。 Linux进程优先级 Linux 系统中每一个普通进程都有一个静态优先级它被调度器作为参考来调度进程。在内核中调度的优先级区间为**[100,139]**数字越小优先级越高。一个新的进程总是从它的父进程继承此值。此外 Linux 进程优先级还包括动态优先级、实时优先级等各个进程优先级描述如下 静态优先级priority被称为“静态”是因为它不随时间而改变只能由用户进行修改。它指明了在被迫和其他进程竞争 CPU 之前该进程所被允许的时间片的最大值20。动态优先级counter counter 即系统为每个进程运行而分配的时间片。 Linux用它来表示进程的动态优先级。 当进程拥有 CPU 时 counter 就随着时间不断减小当它递减为 0 时标记该进程将重新调度。它指明了在当前时间片中所剩余的时间量最初为 20。实时优先级rt_priority它的变化范围是从 099。任何实时进程的优先级都高于普通的进程。Base time quantum是由静态优先级决定当进程耗尽当前 Base time quantumkernel 会重新分配一个 Base time quantum 给它。静态优先级和 Base time quantum的关系如下所述 当静态优先级120 Base time quantumms (140 – priority) * 20 当静态优先级 120 Base time quantumms (140 – priority) * 5 Linux进程的调度算法 时间片轮转调度算法round-robin SCHED_RR 用于实时进程。系统使每个进程依次地按时间片轮流执行的方式。优先权调度算法 SCHED_NORMAL 用于非实时进程。每次系统都会选择队列中优先级最高的进程运行。 Linux 采用抢占式的优级算法即系统中当前运行的进程永远是可运行进程中优先权最高的进程。先进先出调度算法(FIFO) SCHED_FIFO 用于实时进程。采用 FIFO 调度算法选择的实时进程必须是运行时间较短的进程因为这种进程一旦获得 CPU 就只有等到它运行完或因等待资源主动放弃 CPU 时其他进程才能获得运行机会。
2.5 进程地址空间 Linux 的虚拟地址空间为 04GB其分为内核空间和用户空间两部分。将最高的 1GB从虚拟地址 0xC00000000xFFFFFFFF留给内核使用称为“内核空间”较低的 3GB从虚拟地址 0x000000000xBFFFFFFF留给用户进程使用称为“用户空间”。因为每个进程可以通过系统调用进入内核因此 Linux 内核空间被系统的所有进程共享实际上对于每个进程来说它仍然可以拥有 4GB 的虚拟空间。 虚拟地址空间并不是实际的地址空间在为进程分配地址空间时根据进程需要的空间进行分配 4GB 仅仅是最大限额而已并非一次性将 4GB 分配给进程。一般进程的地址空间总是小于 4GB 的可以通过查看/proc/pid/maps 文件来获悉某个具体进程的地址空间。 进程的地址空间并不对应实际的物理页 Linux 采用Lazy 的机制来分配实际的物理页Demand paging 和“写时复制Copy On Write的技术”从而提高实际内存的使用率。虚拟页和物理页 的对应是通过映射机制来实现的即通过页表进行映射到实际的物理页。因为每个进程都有自己的页表因此可以保证不同进程的相同虚拟地址可以映射到不同的物理页从而为不同的进程都可以同时拥有 4GB 的虚拟地址空间提供了可能。 内核是系统中优先级最高的部分所以内核函数申请动态内存时系统不会推迟这个请求但用户进程申请内存空间时进程的可执行文件被装入后进程不会立即对所有的代码进行访问。因此内核总是尽量推迟给用户进程分配动态空间。内核分配空间时通过__get_free_pages()或 alloc_pages 从分区页框分配器中获得页框 通过 kmem_cache_alloc()或 kmalloc()函数使用 slab 分配器为对象分配块通过 vmalloc()或 vmalloc32()函数获得一块非连续的内存区。 与进程地址空间有关的全部信息都包含在内存描述符的数据结构 mm_structs中。 进程描述符的 mm字段就是指向这个结构。 进程地址空间得创建与删除 内核调用copy_mm()函数建立新进程的所有页表和内存描述符来创建进程的地址空间。 static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
{struct mm_struct * mm, *oldmm;int retval;tsk-min_flt tsk-maj_flt 0;tsk-nvcsw tsk-nivcsw 0;tsk-mm NULL;tsk-active_mm NULL;/*如果是内核线程的子线程则直接退出即 mm 和 active_mm 均为 NULL*/oldmm current-mm;if (!oldmm)return 0;/*内核线程只是增加当前进程的虚拟空间的引用计数*/if (clone_flags CLONE_VM) {/*如果共享内存将 mm 由父进程赋值给子进程两个进程将会指向同一块内存*/atomic_inc(oldmm-mm_users);mm oldmm;goto good_mm;}retval -ENOMEM;mm dup_mm(tsk); /*完成了对 vm_area_struct 和页面表的复制*/if (!mm)goto fail_nomem;
good_mm:/* Initializing for Swap token stuff */mm-token_priority 0;mm-last_interval 0;/*内核线程的 mm 和 active_mm 指向当前进程的 mm_struct 结构*/tsk-mm mm;tsk-active_mm mm;return 0;fail_nomem:return retval;
}内核调用 exit_mm()函数释放进程的地址空间 static void exit_mm(struct task_struct * tsk)
{m_release(tsk, mm);/*得到读写信号量*/down_read(mm-mmap_sem);core_state mm-core_state;if (core_state) {struct core_thread self;/*释放读写信号量*/up_read(mm-mmap_sem);self.task tsk;self.next xchg(core_state-dumper.next, self);if (atomic_dec_and_test(core_state-nr_threads))complete(core_state-startup);for (;;) {set_task_state(tsk, TASK_UNINTERRUPTIBLE);if (!self.task) /*take 字段可以查看函数 coredump_finish()*/break;schedule();}__set_task_state(tsk, TASK_RUNNING);down_read(mm-mmap_sem);}atomic_inc(mm-mm_count);BUG_ON(mm ! tsk-active_mm);/* more a memory barrier than a real lock */task_lock(tsk);tsk-mm NULL;up_read(mm-mmap_sem);enter_lazy_tlb(mm, current);/*释放用户虚拟空间的数据结构*/clear_freeze_flag(tsk);task_unlock(tsk);mm_update_next_owner(mm);/*递减 mm 的引用计数并是否为 0如是则释放 mm 所代表的映射*/mmput(mm);
}