最近有日子没写博客了,这段时间有点事忙活一阵子,好在已经接近尾声。也该轮到投些时间好好研究下真刀真枪的东西,干些有意义的事。这两天抽时间继续往下看了看 Linux 内核和 Unix 编程的书,边看边琢磨,想到个关于进程在 fork 子进程或 pthread 出 lwp 时父亲进程的栈段是如何处理的问题,结合 Linux 内核的说明对这个问题有了明确的理解,在此做个笔记。大家也一起研究、分享下~
历史上来说,*nix 里的 C 程序进程由以下几部分组成:
- 正文段。也有叫代码段的。存放着 CPU 执行的机器指令。它一般是共享、只读的。
- 初始化数据段。存放着程序中明确赋初值的变量。
- 非初始化数据段。也叫 bss ,存放着 C 函数之外的变量,内核会初始它为 0 填充。
- 栈段。存放 auto 变量或函数调用传递的信息。包括返回值、实参,调用者上下文(忽然想到,闭包变量会用这个传递么?请教 guru),这些变量会存在一个 stack frame 中。
- 堆段。用于 sbrk (malloc) 等动态内存分配的。
这图说明了这些段的典型的布局。在 x86 CPU 的 Linux 中栈底位于 0xc0000000 开始,该地址以上存储的就是内核代码了(那段线性地址直接映射到物理地址)。当我看到这里的时候,困惑的问题是,在这种段结构中,当我们父进程生成多进程/线程的子进程时,linux 内核对这个父进程的 stack 段是怎么处理了,来保证每个不同进程/线程中的方法调用时,用 stack 来传递的调用信息不会混乱,怎么保证竞争条件下的正确入/出栈顺序?呵呵,现在看来当时的想法比较可笑了。正确理解如下所述。
*nix 有3种进程创建方式:
- fork。内核为父进程创建副本,即子进程。传统情况下,该子进程将获得父进程完整复制,包括数据段(初始化和bss 段)和堆栈段。但是,由于 fork 之后经常跟着就是 execve 系统调用,因此现在的 *nix 会使用 COW(写时复制) 方式来 fork 子进程,也就是这些区域暂时不复制,并由内核将它们只读,当父/子进程对他们修改时,就将修改的部分保存在本次修改操作的进程地址空间中,通常单位是一页。内核为了提高性能,如果父子进程在同一颗 CPU 上的话呢(同 CPU 进程队列),会在 TASK_RUNNING 进程链中将子进程放在放在父进程的前边,这样可减少不必要的 COW 开销。此外还有一些其它属性也将由子进程继承,如实际、有效用户/组 ID,会话 ID,工作目录,环境,连接的共享存储段,资源限制等等。
- lwp。轻量进程允许父子进程共享内核的在部分数据,页表(可共享全局数据),文件描述符表等。pthead 就是通过 lwp 实现的。
- vfork。apue2中将 vfork 单提了来,个人觉得实际和 fork 是一要的,只不过是简版的。通过它创建的子进程能够共享父进程内存地址空间,但为了避免父子混乱,子进程暂时阻塞了父进程执行,直到子进程退出父进程再在此基础上继续执行。
实际上看到这里,已经能够很清楚的解释我上面的疑问了,呵呵。fork 方式会独立出父子进程,vfork 会顺序执行。那么 fork/lwp 的具体细节内核是怎么做到的呢,继续挖。
Linux 通过 clone 系统调用来创建 lwp,而 clone、fork、vfork 都是由 do_fork 内核函数来统一处理完成的,而 do_fork 又是由 copy_process 函数来完成功能的。再看一眼上面我最初想到的问题,已经知道 fork 会出来两个独立的用户进程空间,因此父子进程的栈段肯定不重复。但 lwp 怎么保证栈段不重复的呢,就是通过 clone 系统调用的 child_stack、tls 和 flags 参数来控制的,详细说明看文档和内核源码吧。Linux 中子进程的具体创建步骤说明可见《Understanding The Linux Kernel》 3th 的 P123 很详尽有看起来也有力道,呵呵。
现在关于这个 tls 还有没理解的地方,在 GDT 中共有 3 个 TLS ,段选择符 0x33 - 0x43(那也就是说只允许最多 3 个线程局部数据段),这个 clone 的 tls 参数是传递的什么值,是 GDT 中 tls 的段描述符地址么?
研究的还很 top,很多知识点很模糊 ,且待我继续深入~ 期待哪位牛人能够赐教一二。
// 2009.04.21 21:50 添加 ////
作者:lzy.je
出处:http://lzy.iteye.com
本文版权归作者所有,只允许以摘要和完整全文两种形式转载,不允许对文字进行裁剪。未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
// 2009.04.21 21:52 添加 ////
找插图的时候无意搜到一篇很好的文章,推荐之。
缓冲区溢出深入理解
// 2010.01.06 12:49 添加 ////
全局变量 a[10] 定义区别在 elf 目标文件 .data 和 .bss 段内分配对比。
int a[10]
text data bss dec hex
836 260 72 1168 490
int a[10] = {0};
text data bss dec hex
836 260 72 1168 490
int a[10] = {1};
text data bss dec hex
836 324 8 1168 490
int a[10] = {1, 2, 4, 5, 6, 7, 8, 9, 10};
text data bss dec hex
836 324 8 1168 490
- 大小: 17.3 KB
分享到:
相关推荐
Linux利用进程栈和线程栈来管理这些信息,并通过内核栈来处理系统调用和中断处理。 总的来说,栈作为一种内存管理机制,在Linux系统中扮演着基础而重要的角色。它不仅支撑了程序内部的函数调用过程,更是操作系统多...
Linux 多进程多线程编程 Linux 多进程多线程编程是指在 Linux 操作系统下使用 C 语言进行多进程和多线程编程的技术。该技术可以大幅度提高程序的执行效率和响应速度,提高系统的并发能力和资源利用率。 1. 创建...
LINUX系统下多线程与多进程性能分析 本文主要讨论了Linux操作系统下多线程和多进程的性能分析。在Linux系统中,使用多进程处理多个任务,会占用很多系统资源(主要是CPU和内存的使用)。因此,Linux系统对这种弊端...
2. 创建和销毁:创建和销毁进程开销较大,而线程的创建和销毁速度快得多。 3. 通信:进程间通信需要借助IPC机制,而线程间可以直接访问共享内存,通信更便捷。 4. 调度:操作系统调度线程比调度进程更快,因为线程上...
Windows 操作系统的进程和线程模型被描述成“多进程,基于单进程的多线程”。创建一个进程时,Windows 会做大量的工作,包括创建一个新的地址空间,为进程分配资源以及创建一个基线程。CreateProcess 函数是创建进程...
在嵌入式Linux系统中,使用线程可以提高资源利用率,实现并发执行,例如在一个进程中创建多个线程来处理不同的任务,如网络I/O、用户界面更新等。线程间的协作和同步可以通过互斥锁、条件变量、信号量等机制实现。 ...
在Linux操作系统中,多进程和多线程是两种并发执行的方式,它们在处理并发问题时,经常需要进行同步和互斥操作,以确保数据的一致性和程序的正确性。本篇将详细介绍这两种并发模型以及如何在Linux环境中实现同步互斥...
### C语言多进程多线程编程相关知识点 #### 进程与线程的基本概念 - **进程**: 进程是一个程序在计算机上的一次执行活动。它是系统进行资源分配和调度的基本单位,拥有独立的地址空间和其他资源。进程之间相互独立...
在多进程或多线程环境中,进程或线程之间需要进行通信和同步,以确保数据的一致性和程序的正确运行。Linux提供了多种机制来实现进程间通信(IPC),包括信号、管道、消息队列、共享内存和信号量等。 #### 线程管理 ...
代码目的是比较write和printf多路写性能。首先fork生成子进程,并且在子进程中重定向标准输出;然后在父子进程中各创建10个线程分别利用printf和write进行写操作;最后通过返回值比较两者性能。
### Linux下多进程、多线程编程 #### 进程结构理解 在深入探讨Linux下的多进程和多线程编程之前,我们先来了解一下Linux进程的基本结构。在Linux环境中,每一个进程都拥有独立的地址空间,这个地址空间可以被划分...
Linux下多线程及多进程及同步与互斥编程详细介绍
Linux作为一个多用户多任务的现代操作系统,其进程和线程的管理是系统设计的重要组成部分。在Linux中,进程管理涉及进程的创建、执行、状态转换和退出等,而线程作为一种轻量级的进程,为程序并发执行提供了条件。...
在操作系统课程设计中,Linux进程与线程的通信是一个核心且复杂的主题。在这个项目中,学生将深入理解操作系统内核如何管理和协调不同进程和线程之间的数据交换,从而实现高效的任务执行。以下是对这个主题的详细...
在Linux操作系统中,进程间通信(IPC,Inter-Process Communication)和多线程编程是实现高效并发处理的关键技术。本文将深入探讨这两种技术,并结合"全双工邮箱通讯"的源码实例,来阐述如何利用它们实现数据交换。 ...
本文将深入探讨Linux环境中的多线程概念、创建与管理线程的方法、线程同步与通信机制,以及多线程编程中可能遇到的问题和解决策略。 一、多线程概念 多线程是指在一个进程中可以同时执行多个独立的代码段,每个代码...
学习资料中的"Linux多线程学习(一)"可能涉及了基础知识和创建线程的概念;"Linux多线程学习(二)"可能深入讲解了线程属性和如何初始化;"Linux多线程学习(三)"可能介绍互斥锁的使用和示例;"Linux多线程学习...