进程调度之linux操作系统的进程与线程基本概念
来源:互联网 发布:海盗战 知乎 编辑:程序博客网 时间:2024/05/29 08:32
进程是具有独立地址空间的;线程没有独立地址空间,一种说法是内核里面只有线程,因为内核的地址空间是共享的(其实操作系统里面很多实现没有非黑即白的概念)。
有两篇文章写得很好
http://blog.csdn.net/u012927281/article/details/51602898
http://www.2ndmoon.net/weblog/?p=603
关于进程的子进程的补充:
parent、sibling、children都是task_struct中的成员,其中parent是task_struct指针,sibling和children都是list_head结构体。
有趣是因为,除了parent比较容易理解之外,另外两个都“不太正常”。
- sibling.next指向进程的下一个兄弟进程的进程描述符sibling成员,若其后没有其他兄弟进程,则指向父进程;而sibling.prev指向进程的上一个兄弟进程,若其之前没有兄弟进程,则指向父进程。
- children.next指向父进程的第一个子进程的sibling成员(而不是children成员!),而children.prev却指向父进程的最后一个子进程的sibling成员。
创建子进程do_fork =>p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); =>p = dup_task_struct(current); =>ti = alloc_thread_info_node(tsk, node); =>err = arch_dup_task_struct(tsk, orig); =>setup_thread_stack(tsk, orig);//8K内核堆栈区 =>sched_fork(p); =>p->state = TASK_RUNNING;//子进程为就绪态 =>pid = alloc_pid(p->nsproxy->pid_ns);//申请pid =>pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); =>nr = alloc_pidmap(tmp); =>hlist_add_head_rcu(&upid->pid_chain, &pid_hash[pid_hashfn(upid->nr, upid->ns)]); =>retval = copy_thread(clone_flags, stack_start, stack_size, p, regs); =>wake_up_new_task(p);//将新的子进程加入就绪队列 =>rq = __task_rq_lock(p); =>activate_task(rq, p, 0); =>enqueue_task(rq, p, flags); =>p->sched_class->enqueue_task(rq, p, flags);//进入就绪队列创建内核线程//powerpc的做法kernel_thread =>mr r30,r3 /* function *///压栈,系统调用sys_clone mr r31,r4 /* argument */ ori r3,r5,CLONE_VM /* flags */ oris r3,r3,CLONE_UNTRACED>>16 li r4,0 /* new sp (unused) */ li r0,__NR_clone sc =>sys_clone =>do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp);//X86的做法kernel_thread =>regs.orig_ax = -1; regs.ip = (unsigned long) kernel_thread_helper; regs.cs = __KERNEL_CS | get_kernel_rpl(); regs.flags = X86_EFLAGS_IF | 0x2; =>do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);关于switch_toschedule =>preempt_disable(); =>cpu = smp_processor_id(); rq = cpu_rq(cpu); =>prev = rq->curr; =>next = pick_next_task(rq);//按照策略算法选择下一个要切换的进程 =>context_switch(rq, prev, next);//切换 =>switch_to(prev, next, prev); =>(last) = __switch_to((prev), (next)) =>new_thread = &new->thread; old_thread = ¤t->thread; =>last = _switch(old_thread, new_thread); =>stw r1,KSP(r3) /* Set old stack pointer */ =>lwz r1,KSP(r4) /* Load new stack pointer */ =>lwz r4,_NIP(r1) /* Return to _switch caller in new task */ =>DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); =>#define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) thread_struct { ... struct pt_regs *regs; ... } struct pt_regs { ... unsigned long nip; unsigned long msr; ... } mtlr r4 addi r1,r1,INT_FRAME_SIZE blr =>preempt_enable_no_resched();
copy_thread初始化子进程的内核栈,和新进程的正文段在linux的核心空间,与其它核心进程以及linux内核共享相同的核心正文段。
进程切换只发生在内核态,在执行进程切换之前,用户态进程使用的所有寄存器内容都已经保存在内核态堆栈上,包括用户态进程的SS和ESP寄存器。
Linux系统存在两类用户进程,用户进程和用户线程。严格意义上说,只有拥有了进程描述符,PID,进程正文端,用户进程的数据段和栈段,核心栈段的进程才被称为用户进程,二没有独立数据段和栈段的进程被称为线程。
LINUX系统中,进程和线程都有自己的进程描述符与核心栈段。其中,核心栈段用来支持用户进程或线程在LINUX核心中执行。
关于switch_to,下面这篇文章讲得挺好
linux内核——进程切换宏switch_to
http://www.cnblogs.com/ISeeIC/p/3625556.html
参考如下博客:
task_struct与进程关系
http://blog.csdn.net/seayoungsjtu/article/details/51077840
关于thread_info结构
Linux进程内核栈与thread_info结构详解–Linux进程的管理与调度(九)
http://blog.csdn.net/gatieme/article/details/51577479
linux内核分析笔记—-进程管理
http://www.cnblogs.com/hanyan225/archive/2011/07/09/2101962.html
- 进程调度之linux操作系统的进程与线程基本概念
- 操作系统之进程与线程4——进程调度
- 操作系统之进程的调度与死锁
- 《Linux操作系统分析》之理解进程调度时机跟踪分析进程调度与进程切换的过程
- JAVA线程管理与操作系统的进程调度<持续更新>
- 进程与线程的基本概念
- 进程与线程的基本概念
- 操作系统之进程与线程
- 操作系统进程与线程之进程篇
- 操作系统 进程管理之进程与线程
- 操作系统 3. 线程基本概念; 线程于进程的比较; 用户线程与内核线程; 线程模型
- 操作系统之进程调度
- 操作系统之进程调度
- 操作系统的进程与线程
- 操作系统的线程与进程
- 聊聊Linux操作系统对进程的调度
- 操作系统进程与线程之线程篇
- 读书笔记-现代操作系统-2进程与线程-2.4调度
- android四大组件之intent
- 写文章 【500万花落谁家】京东金融——中信量化策略大赛等你来战
- HDU 1016
- 算法导论程序23--有根树的表示(Python)
- BZOJ2820: YY的GCD
- 进程调度之linux操作系统的进程与线程基本概念
- xml
- IO流应用-文件夹的复制
- 自定义TabLayout的tab标签内容在点击的时候出现灰色背景
- jQuery的属性与样式之.val()
- h5 web 存储
- MFC框架机制详解
- Java线程(初识)
- 树结构练习——排序二叉树的中序遍历