LWP 轻量级线程的意义与实现

转子 http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/

二.Linux 2.4内核中的轻量进程实现

最初的进程定义都包含程序、资源及其执行三部分,其中程序通常指代码,资源在操作系统层面上通常包括内存资源、IO资源、信号处理等部分,而程序的执行通常理解为执行上下文,包括对cpu的占用,后来发展为线程。在线程概念出现以前,为了减小进程切换的开销,操作系统设计者逐渐修正进程的概念,逐渐允许将进程所占有的资源从其主体剥离出来,允许某些进程共享一部分资源,例如文件、信号,数据内存,甚至代码,这就发展出轻量进程的概念。Linux内核在2.0.x版本就已经实现了轻量进程,应用程序可以通过一个统一的clone()系统调用接口,用不同的参数指定创建轻量进程还是普通进程。在内核中,clone()调用经过参数传递和解释后会调用do_fork(),这个核内函数同时也是fork()、vfork()系统调用的最终实现:

<linux-2.4.20/kernel/fork.c>
int do_fork(unsigned long clone_flags, unsigned long stack_start,
struct pt_regs *regs, unsigned long stack_size)

其中的clone_flags取自以下宏的"或"值:

<linux-2.4.20/include/linux/sched.h>
#define CSIGNAL      0x000000ff
/* signal mask to be sent at exit */
#define CLONE_VM    0x00000100
/* set if VM shared between processes */
#define CLONE_FS        0x00000200
/* set if fs info shared between processes */
#define CLONE_FILES     0x00000400
/* set if open files shared between processes */
#define CLONE_SIGHAND  0x00000800
/* set if signal handlers and blocked signals shared */
#define CLONE_PID    0x00001000
/* set if pid shared */
#define CLONE_PTRACE  0x00002000
/* set if we want to let tracing continue on the child too */
#define CLONE_VFORK  0x00004000
/* set if the parent wants the child to wake it up on mm_release */
#define CLONE_PARENT  0x00008000
/* set if we want to have the same parent as the cloner */
#define CLONE_THREAD  0x00010000
/* Same thread group? */
#define CLONE_NEWNS  0x00020000  /* New namespace group? */
#define CLONE_SIGNAL   (CLONE_SIGHAND | CLONE_THREAD)

在do_fork()中,不同的clone_flags将导致不同的行为,对于LinuxThreads,它使用(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)参数来调用clone()创建"线程",表示共享内存、共享文件系统访问计数、共享文件描述符表,以及共享信号处理方式。本节就针对这几个参数,看看Linux内核是如何实现这些资源的共享的。

1.CLONE_VM

do_fork()需要调用copy_mm()来设置task_struct中的mm和active_mm项,这两个mm_struct数据与进程所关联的内存空间相对应。如果do_fork()时指定了CLONE_VM开关,copy_mm()将把新的task_struct中的mm和active_mm设置成与current的相同,同时提高该mm_struct的使用者数目(mm_struct::mm_users)。也就是说,轻量级进程没有独立的文件系统相关的信息,进程中任何一个线程改变当前目录、根目录等信息都将直接影响到其他线程。

3.CLONE_FILES

一个进程可能打开了一些文件,在进程结构task_struct中利用files(struct files_struct *)来保存进程打开的文件结构(struct file)信息,do_fork()中调用了copy_files()来处理这个进程属性;轻量级进程与父进程是共享该结构的,copy_files()时仅增加files->count计数。这一共享使得任何线程都能访问进程所维护的打开文件,对它们的操作会直接反映到进程中的其他线程。

4.CLONE_SIGHAND

每一个Linux进程都可以自行定义对信号的处理方式,在task_struct中的sig(struct signal_struct)中使用一个struct k_sigaction结构的数组来保存这个配置信息,do_fork()中的copy_sighand()负责复制该信息;轻量级进程不进行复制,而仅仅增加signal_struct::count计数,与父进程共享该结构。也就是说,子进程与父进程的信号处理方式完全相同,而且可以相互更改。

do_fork()中所做的工作很多,在此不详细描述。对于SMP系统,所有的进程fork出来后,都被分配到与父进程相同的cpu上,一直到该进程被调度时才会进行cpu选择。

尽管Linux支持轻量级进程,但并不能说它就支持核心级线程,因为Linux的"线程"和"进程"实际上处于一个调度层次,共享一个进程标识符空间,这种限制使得不可能在Linux上实现完全意义上的POSIX线程机制,因此众多的Linux线程库实现尝试都只能尽可能实现POSIX的绝大部分语义,并在功能上尽可能逼近。

LWP 轻量级线程的意义与实现

时间: 2024-10-12 03:41:58

LWP 轻量级线程的意义与实现的相关文章

并发——轻量级线程,通道,单向通道

1.轻量级线程 goroutine 是 Go语言中的轻量级线程实现,由 Go 运行时(runtime)管理.Go 程序会智能地将 goroutine 中的任务合理地分配给每个 CPU.Go 程序从 main 包的 main() 函数开始,在程序启动时,Go 程序就会为 main() 函数创建一个默认的 goroutine. 1)使用普通函数创建goroutine Go 程序中使用 go 关键字为一个函数创建一个 goroutine.一个函数可以被创建多个 goroutine,一个 gorouti

轻量级线程和重量级线程的定义是什么,他们的区别是什么?如何区分?

通常说java的是重量级线程,python,erlang等是轻量级线程,请问为什么这样说?他们的区别是什么?如何区分重量级线程和轻量级线程? 轻量级线程和重量级线程的定义是什么,他们的区别是什么?如何区分? >> golang 这个答案描述的挺清楚的:http://www.goodpm.net/postreply/golang/1010000008937736/轻量级线程和重量级线程的定义是什么他们的区别是什么如何区分.html

Linux下的进程类别(内核线程、轻量级进程和用户进程)以及其创建方式--Linux进程的管理与调度(四)

本文声明 日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的创建 本文中出现的,内核线程,轻量级进程,用户进程,用户线程等概念,如果不太熟悉, 可以参见 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux进程类别 虽然我们在区分Linux进程类别, 但是我还是想说Linux下只有一种类型的进程,那就是task_str

进程、线程、轻量级进程、协程和go中的Goroutine

一.进程 操作系统中最核心的概念是进程,分布式系统中最重要的问题是进程间通信. 进程是“程序执行的一个实例” ,担当分配系统资源的实体.进程创建必须分配一个完整的独立地址空间. 进程切换只发生在内核态,两步:1 切换页全局目录以安装一个新的地址空间 2 切换内核态堆栈和硬件上下文.  另一种说法类似:1 保存CPU环境(寄存器值.程序计数器.堆栈指针)2修改内存管理单元MMU的寄存器 3 转换后备缓冲器TLB中的地址转换缓存内容标记为无效. 二.线程 书中的定义:线程是进程的一个执行流,独立执行

【转】linux 用户线程、LWP、内核线程学习笔记

[好文转发---linux 用户线程.LWP.内核线程学习笔记] 在现代操作系统中,进程支持多线程.进程是资源管理的最小单元:而线程是程序执行的最小单元.一个进程的组成实体可以分为两大部分:线程集合资源集.进程中的线程是动态的对象:代表了进程指令的执行.资源,包括地址空间.打开的文件.用户信息等等,由进程内的线程共享. 线程有自己的私有数据:程序计数器,栈空间以及寄存器. Why Thread?(传统单线程进程的缺点) 1. 现实中有很多需要并发处理的任务,如数据库的服务器端.网络服务器.大容量

Java的线程模型

并发不一定要依赖多线程(如PHP中很常见的多进程并发),但是在Java里面谈论并发,大多数都与线程脱不开关系. 线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址.文件I/O等),又可以独立调度(线程是CPU调度的基本单位). 主流的操作系统都提供了线程实现,Java语言则提供了在不同硬件和操作系统平台下对线程操作的统一处理,每个已经执行start()且还未结束的java.lang.Thread类的实例就代表了一个线程.我

jvm(12)-java内存模型与线程

[0]README 0.1)本文部分文字描述转自“深入理解jvm”,旨在学习“java内存模型与线程” 的基础知识: [1]概述 1)并发处理的广泛应用是使得 Amdahl 定律代替摩尔定律称为计算机性能发展源动力的根本原因: 2)Amdahl 定律:该定律通过系统中并行化与串行化的比重来描述多处理器系统能获得的运算加速能力: 3)摩尔定律:该定律用于描述处理器晶体管数量与运行效率间的发展关系: Conclusion)这两个定律的更替代表了近年来硬件发展从追求处理器频率到追求多核心并行处理的发展

Java线程与锁

Java线程与锁 本篇是 <深入理解Java虚拟机>的最后一章, 在此涉及到了线程安全, 但并不是如何从代码层次来实现线程安全, 而是虚拟机本身对线程安全做出了哪些努力, 在安全与性能之间又采取了哪些优化措施. 那么一步步来梳理这些概念. 三种线程概念--内核线程.轻量级进程.用户线程 参考 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux下的进程类别(内核线程.轻量级进程和用户进程)以及其创建方式--Linux进程的管理与调度(四) 内核线程(Kernel-Le

JVM——java内存模型和线程

概述 计算机的运算速度与它的存储和通信子系统速度的差距太大,大量的时间都花费在磁盘I/O.网络通信或者数据库访问上.我们当然不希望处理器大部分时间都处于等待其他资源的状态,要通过一些“手段”去把处理器的运算能力“压榨”出来,不然太浪费了. 衡量一个服务性能的高低好坏,每秒事务处理数(Transactions Per Second,TPS)是最重要的指标之一.代表一秒服务端平均能响应的请求总数,而TPS值与程序的并发能力又有密切的相关. 硬件的效率与一致性 处理器要和内存交互(取运算数据.存储运算