linux 线程的内核栈是独立的还是共享父进程的?
需要考证
考证结果:
其内核栈是独立的
206 static struct task_struct *dup_task_struct(struct task_struct *orig)
207 {
208 struct task_struct *tsk;
209 struct thread_info *ti;
210 int err;
211
212 prepare_to_copy(orig);
213
214 tsk = alloc_task_struct();
215 if (!tsk)
216 return NULL;
217
218 ti = alloc_thread_info(tsk);
219 if (!ti) {
220 free_task_struct(tsk);
221 return NULL;
222 }
223
224 err = arch_dup_task_struct(tsk, orig);
225 if (err)
226 goto out;
227
228 tsk->stack = ti;
229
230 err = prop_local_init_single(&tsk->dirties);
231 if (err)
232 goto out;
233
234 setup_thread_stack(tsk, orig);
。。。。。。。、 98 #ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATOR
99 static inline struct thread_info *alloc_thread_info(struct task_struct *tsk)
100 {
101 #ifdef CONFIG_DEBUG_STACK_USAGE
102 gfp_t mask = GFP_KERNEL | __GFP_ZERO;
103 #else
104 gfp_t mask = GFP_KERNEL;
105 #endif
106 return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
107 }
108
。。。。。。
Breakpoint 2, __get_free_pages (gfp_mask=208, order=1) at mm/page_alloc.c:1670
1670 page = alloc_pages(gfp_mask, order);
(cskygdb) bt
#0 __get_free_pages (gfp_mask=208, order=1) at mm/page_alloc.c:1670
#1 0x9000f5d6 in alloc_thread_info (clone_flags=4001536, stack_start=7, regs=0x0, stack_size=715825152, child_tidptr=0x0, pid=0x0, trace=0)
at kernel/fork.c:106
#2 dup_task_struct (clone_flags=4001536, stack_start=7, regs=0x0, stack_size=715825152, child_tidptr=0x0, pid=0x0, trace=0)
at kernel/fork.c:218
#3 copy_process (clone_flags=4001536, stack_start=7, regs=0x0, stack_size=715825152, child_tidptr=0x0, pid=0x0, trace=0)
at kernel/fork.c:922
#4 0x90010a7e in do_fork (clone_flags=4001536, stack_start=715921168, regs=0x90847fb8, stack_size=0, parent_tidptr=0x2aac1be8,
child_tidptr=0x2aac1be8) at kernel/fork.c:1348
#5 0x90005c4e in csky_clone (clone_flags=<value optimized out>, newsp=<value optimized out>, parent_tidptr=<value optimized out>,
child_tidptr=0x90005c4e, tls_val=<value optimized out>, regs=<value optimized out>) at arch/csky/kernel/process.c:237
#6 0x900009d2 in system_call ()
网上的介绍:
http://www.360doc.com/content/13/0527/00/12499915_288433220.shtml
linux 线程有自己独立的内核栈吗?
首先,我们知道所有线程共享主线程的虚拟地址空间(current->mm指向同一个地址),且都有自己的用户态堆栈(共享父进程的地址空间,再在里面分配自己的独立栈,默认2M)。这是毫无疑问的,但还有一点我没搞明白,内核栈是共享还是独立的?
猜测:独立的。理由:要不然内核栈对应的thread_info中的tast_struct没有办法与每个线程对应起来,因为现在已经有多个task_struct了,但保存内核栈的thread_info(其实是thread_union联合体)中只能保存一个task_struct。所以理论上分析,虽然可以共享地址空间,但每个线程还是需要一个单独的内核栈的。看代码:
分析创建线程最终肯定会走到内核函数do_fork()中来的,所以从此函数看起。
do_fork()->copy_process()->dup_task_struct()
fork.c中dup_task_struct()的实现:
static struct task_struct *dup_task_struct(struct task_struct *orig)
{
struct task_struct *tsk;
struct thread_info *ti;
unsigned long *stackend;
int node = tsk_fork_get_node(orig);
int err; tsk = alloc_task_struct_node(node);
if (!tsk)
return NULL; ti = alloc_thread_info_node(tsk, node);/*就是这里,果然分配内核栈了*/
if (!ti)
goto free_tsk; err = arch_dup_task_struct(tsk, orig);/*这里分配task_struct结构*/
if (err)
goto free_ti; tsk->stack = ti;
...
}
线程在Linux中的实现
3.3 线程在Linux中的实现
线程机制是现代编程技术中常用的一种抽象。该机制提供了在同一程序内共享内存地址空间运行的一组线程。这些线程还可以共享打开的文件和其他资源。线 程机制支持并发程序设计技术(concurrent programming),在多处理器系统上,它也能保证真正的并行处理(parallelism)。
Linux实现线程的机制非常独特。从内核的角度来说,它并没有线程这个概念。Linux把所有的线程都当作进程来实现。内核并没有准备特别的调度 算法或是定义特别的数据结构来表征线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有惟一隶属于自己的 task_struct,所以在内核中,它看起来就像是一个普通的进程(只是该进程和其他一些进程共享某些资源,如地址空间)。
上述线程机制的实现与Microsoft Windows或是Sun Solaris等操作系统的实现差异非常大。这些系统都在内核中提供了专门支持线程的机制(这些系统常常把线程称作轻量级进程,lightweight process)。“轻量级进程”这种叫法本身就概括了Linux在此处与其他系统的差异。在其他的系统中,相较于重量级的进程,线程被抽象成一种耗费较 少资源,运行迅速的执行单元。而对于Linux来说,它只是一种进程间共享资源的手段(Linux的进程本身就够轻了)。举个例子来说,假如我们有一个包 含四个线程的进程,在提供专门线程支持的系统中,通常会有一个包含指向四个不同线程的指针的进程描述符。该描述符负责描述像地址空间、打开的文件这样的共 享资源。线程本身再去描述它独占的资源。相反,Linux仅仅创建四个进程并分配四个普通的task_sturct结构。建立这四个进程时指定它们共享某 些资源就行了。
线程的创建和普通进程的创建类似,只不过在调用clone()的时候需要传递一些参数标志来指明需要共享的资源:
- clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
上面的代码产生的结果和调用fork()差不多,只是父子俩共享地址空间、文件系统资源、文件描述符和信号处理程序。换个说法就是,新建的进程和它的父进程就是流行的所谓线程。
对比一下,一个普通的fork()的实现是:
- clone(SIGCHLD, 0);
而vfork()的实现是:
- clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0);
传递给clone()的参数标志决定了新创建进程的行为方式和父子进程之间共享的资源种类。表3-1列举了这些clone()用到的参数标志以及它们的作用,这些是在<linux/sched.h>中定义的。
linux 线程的内核栈是独立的还是共享父进程的?的更多相关文章
- linux线程的实现
首先从OS设计原理上阐明三种线程:内核线程.轻量级进程.用户线程 内核线程 内核线程就是内核的分身,一个分身可以处理一件特定事情.这在处理异步事件如异步IO时特别有用.内核线程的使用是廉价的,唯一使用 ...
- linux线程的实现【转】
转自:http://www.cnblogs.com/zhaoyl/p/3620204.html 首先从OS设计原理上阐明三种线程:内核线程.轻量级进程.用户线程 内核线程 内核线程就是内核的分身,一个 ...
- linux线程的实现(转)
原文:https://www.cnblogs.com/zhaoyl/p/3620204.html 首先从OS设计原理上阐明三种线程:内核线程.轻量级进程.用户线程 内核线程 内核线程就是内核的分身,一 ...
- 【转】linux线程模型
一.定义 关于进程.轻量级进程.线程.用户线程.内核线程的定义,这个很容易找到,但是看完之后你可以说你懂了,但实际上你真的明白了么? 在现代操作系统中,进程支持多线程.进程是资源管理的最小单元:而线程 ...
- Linux 线程浅析
进程和线程的区别与联系 在许多经典的操作系统教科书中,总是把进程定义为程序的执行实例,它并不执行什么, 只是维护应用程序所需的各种资源,而线程则是真正的执行实体. 为了让进程完成一定的工作,进程必须至 ...
- POSIX 线程详解 一种支持内存共享的简捷工具
线程是有趣的 了解如何正确运用线程是每一个优秀程序员必备的素质.线程类似于进程.如同进程,线程由内核按时间分片进行管理.在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同.而 ...
- Python 第八篇:异常处理、Socket语法、SocketServer实现多并发、进程和线程、线程锁、GIL、Event、信号量、进程间通讯
本节内容: 异常处理.Socket语法.SocketServer实现多并发.进程和线程.线程锁.GIL.Event.信号量.进程间通讯.生产者消费者模型.队列Queue.multiprocess实例 ...
- linux 线程基础
线程基础函数 查看进程中有多少个线程,查看线程的LWP ps -Lf 进程ID(pid) 执行结果:LWP列 y:~$ ps -Lf 1887 UID PID PPID LWP C NLWP STIM ...
- [转载]Linux 线程实现机制分析
本文转自http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 支持原创.尊重原创,分享知识! 自从多线程编程的概念出现在 Linux ...
随机推荐
- jQuery ui datepicker 日历转中文
做个笔记,以后详解 jQuery(function($){ $.datepicker.regional['zh-CN'] = { closeText: '关闭', prevText: '<上月' ...
- 初识NoSQL 快速认识NoSQL数据库 分析Analytics For Hackers: How To Think About Event Data
做了一年的大一年度项目了,对于关系型数据库结构还是有些了解了,有的时候还是觉得这种二维表不是很顺手.在看过一篇文章之后,对NoSQL有了初步的了解,(https://keen.io/blog/5395 ...
- HBase多条件筛选查询方案
最近的项目需要使用Hbase做实时查询,由于Hbase只支持一级索引,也就是使用rowkey作为索引查询,所以对于多条件筛选查询的支持不够,在不建立二级索引的情况下,只能使用Hbase API中提供的 ...
- phpcms v9 源码解析(4)content模块下的index.php文件的init()方法解析
在了解index.php中的init函数的时候,让我们先看看最开始的几行代码 1-5 第二行, defined('IN_PHPCMS') or exit('Nopermission resource ...
- openerp经典收藏 深入理解报表运行机制(转载)
深入理解报表运行机制 原文:http://blog.sina.com.cn/s/blog_57ded94e01014ppd.html 1) OpenERP报表的基本运行机制 OpenERP报表的 ...
- python 数字、字符串、列表常用函数
一.数字的标准类型: cmp():比较两个数的大小:返回值(-1,0,1). str():数字转化成字符串. type():返回数字类型. 转换工厂函数: int(obj,base=10) long( ...
- TAG的用法和用途[转]
用一个例子来说明:一个combobox控件...一个textBox控件...一个datagridview控件!datagridview控件是连接数据库的...combobox和textBox是联合查询 ...
- C#的winform小合集
C#的winform小合集 博主很懒,又想记录一下自己的所做所为,仅此而已,供自己日后所看.这个是博主自主学习C#所写的一些小程序,有好玩的,也有一些无聊闲得蛋疼所作的. 内容介绍 C#入门窗口输出h ...
- java移位操作符
<<:左移操作符,右边补0,相当于乘二乘二... >>:右移操作符,左边补符号位(正数补0,负数补1),相当于除二除二... >>>:无符号右移,左边补0,相 ...
- java之redis篇(spring-data-redis整合)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...