`
bigfirebird
  • 浏览: 125058 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

linux 2.6进程与线程

阅读更多
1 >    线程和进程的差别
线程机制支持并发程序设计技术,在多处理器上能真正保证并行处理。而在linux实现线程很特别,linux把所有的线程都当作线程实现。
linux下线程看起来就像普通进程(只是该进程和其他进程共享资源,如地址空间)。上述机制与Microsoft windows或是Sun Solaris实现
差异很大。这些系统提供专门支持线程机制(轻量级进程)。

在现代操作系统中,进程支持多线程。进程是资源管理及分配的最小单元;而线程是程序执行的最小单元。一个进程的组成实体可以分为两大部分:线程集和资源集。进程中的线程是动态的对象,代表了进程指令的执行过程。资源,包括地址空间、打开的文件、用户信息等等,由进程内的线程共享。线程有自己的私有数据:程序计数器,栈空间以及寄存器。

现实中有很多需要并发处理的任务,如数据库的服务器端、网络服务器、大容量计算等。

如果采用多进程的方法,则有如下问题:
      1> fork一个子进程的消耗是很大的,fork是一个昂贵的系统调用。
      2> 各个进程拥有自己独立的地址空间,进程间的协作需要复杂的IPC技术,如消息传递和共享内存等。

线程推广了进程的概念,使一个进程可以包含多个活动(或者说执行序列等等)。多线程的优点和缺点实际上是对立统一的。使用线程的优点在于:

      1> 改进程序的实时响应能力;
      2> 更有效的使用多处理器,真正的并行(parallelism);
      3> 改进程序结构,具备多个控制流;
      4> 通讯方便,由于共享进程的代码和全局数据;
      5> 减少对系统资源的使用。对属于同一个进程的线程之间进行调度切换时不需要调用系统调用,因此将减少额外的消耗,往往一个进程可以启动上千个线程也没有什么问题。

缺点在于:
由于各线程共享进程的地址空间,因此可能会导致竞争,因此对某一块有多个线程要访问的数据需要一些同步技术。


2 >     线程的分类
2.1     内核线程
Linux内核可以看作一个服务进程(管理软硬件资源,响应用户进程的种种合理以及不合理的请求)。内核需要多个执行流并行,为了防止可能的阻塞,多线程化是必要的。内核线程就是内核的分身,一个分身可以处理一件特定事情。Linux内核使用内核线程来将内核分成几个功能模块,像kswapd、kflushd等,这在处理异步事件如异步IO时特别有用。内核线程的使用是廉价的,唯一使用的资源就是内核栈和上下文切换时保存寄存器的空间。支持多线程的内核叫做多线程内核(Multi-Threads kernel )。内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位。这与用户线程是不一样的。

2.2用户线程
用户线程在用户空间中实现,内核并没有直接对用户线程进程调度,内核的调度对象和传统进程一样,还是进程本身,内核并不知道用户线程的存在。

由于Linux内核没有轻量级进程(线程)的概念,因此不能独立的对用户线程进行调度,而是由一个线程运行库来组织线程的调度,其主要工作在于在各个线程的栈之间调度。如果一个进程中的某一个线程调用了一个阻塞的系统调用,整个进程就会被调度程序切换为等待状态,其他线程得不到运行的机会。因此linux使用了异步I/O机制。


3 >     内核线程
内核线程(thread)或叫守护进程(daemon),在操作系统中占据相当大的比例,当Linux操作系统启动以后,尤其是X window也启动以后,你可以用”ps -ef”命令查看系统中的进程,这时会发现很多以”d”结尾的进程名,确切说名称显示里面加 "[]"的,这些进程就是内核线程。系统的启动是从硬件->内核->用户态进程的,pid的分配是一个往前的循环的过程,所以随系统启动的内核线程的pid往往很小。

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 09:42 ?        00:00:01 /sbin/init
root         2     0  0 09:42 ?        00:00:00 [kthreadd]
root         3     2  0 09:42 ?        00:00:00 [migration/0]
root         4     2  0 09:42 ?        00:00:00 [ksoftirqd/0]
root         5     2  0 09:42 ?        00:00:00 [watchdog/0]
root         6     2  0 09:42 ?        00:00:00 [events/0]
root         7     2  0 09:42 ?        00:00:00 [khelper]
root        40     2  0 09:42 ?        00:00:00 [kblockd/0]
root        64     2  0 09:42 ?        00:00:00 [kseriod]
root       110     2  0 09:42 ?        00:00:00 [pdflush]
root       111     2  0 09:42 ?        00:00:00 [pdflush]
root       112     2  0 09:42 ?        00:00:00 [kswapd0]
root       151     2  0 09:42 ?        00:00:00 [aio/0]
root      1327     2  0 09:42 ?        00:00:00 [ksuspend_usbd]
root      1330     2  0 09:42 ?        00:00:00 [khubd]
root      1362     2  0 09:42 ?        00:00:00 [ata/0]
root      1370     2  0 09:42 ?        00:00:00 [ata_aux]
root      1428     2  0 09:42 ?        00:00:00 [scsi_eh_0]
root      1430     2  0 09:42 ?        00:00:01 [scsi_eh_1]
root      2304     2  0 09:42 ?        00:00:00 [kjournald]
root      2507     1  0 09:42 ?        00:00:00 /sbin/udevd --daemon
root      2787     2  0 09:42 ?        00:00:00 [kgameportd]
root      3698     2  0 09:42 ?        00:00:00 [kapmd]
root      3872     2  0 09:42 ?        00:00:00 [kjournald]



3.1     内核线程
      events 处理内核事件 很多软硬件事件(比如断电,文件变更)被转换为events,并分发给对相应事件感兴趣的线程进行响应

      ksoftirqd 处理软中断 硬件中断处理往往需要关中断,而这个时间不能太长,否则会丢失新的中断。所以中断处理的很大一部分工作移出,转给任劳任怨的ksoftirqd在中断之外进行处理。比如一个网络包,从网卡里面取出这个过程可能需要关中断,但是TCP/IP协议处理就不必关中断了

      kblockd 管理磁盘块读写

      kjournald Ext3文件系统的日志管理 通常每个 _已mount_ 的 Ext3分区会有一个 kjournald看管,各分区的日志是独立

      pdflush dirty内存页面的回写 太多dirty的页面意味着风险,比如故障时候的内容丢失,以及对突发的大量物理内存请求的响应(大量回写会导致糟糕的响应时间)

      kswapd 内存回收 确保系统空闲物理内存的数量在一个合适的范围

      aio 代替用户进程管理io 用以支持用户态的AIO
     


3.2     用户进程

      crond 执行定时任务

      init 为内核创建的第一个线程。引导用户空间服务,管理孤儿线程,以及运行级别的转换
     
      mingetty 等待用户从tty登录

      bash shell进程,一个命令行形式的系统接口;接受用户的命令,并进行解释、执

      sshd ssh登录、文件传输、命令执行 等操作的服务进程

      klogd 从内核信息缓冲区获取打印信息。内核在发现异常的时候,往往会输出一些消息给用户,这个对于故障处理很有用

      syslogd 系统日志进程

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



long do_fork(unsigned long                   clone_flags,                                                                                                                    unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)


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

在 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)。也就是说,轻量级进程与父进程共享内存地址空间,由下图示意可以看出mm_struct在进程中的地位:

2.CLONE_FS
task_struct 中利用fs(struct fs_struct *)记录了进程所在文件系统的根目录和当前目录信息,do_fork()时调用copy_fs()复制了这个结构;而对于轻量级进程则仅增加 fs->count计数,与父进程共享相同的fs_struct。也就是说,轻量级进程没有独立的文件系统相关的信息,进程中任何一个线程改变当前目录、根目录等信息都将直接影响到其他线程。

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计数,与父进程共享该结构。也就是说,子进程与父进程的信号处理方式完全相同,而且可以相互更改。


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

相关推荐

    Linux2.6内核标准教程(共计8-- 第1个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    Linux2.6内核标准教程(共计8--第8个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    Linux2.6内核标准教程(共计8--第6个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    Linux2.6内核标准教程(共计8--第3个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    Linux2.6内核标准教程(共计8--第7个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    Linux2.6内核实现的是NPTL线程模型

    Linux2.6 内核实现的是 NPTL 线程模型,依然是用进程来模 拟线程 , 但新引入了线程组 ( 进程组 ) 的概念 , 使得实现效率更 好。

    Linux2.6内核标准教程(共计8--第2个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    Linux2.6内核标准教程(共计8--第4个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    Linux2.6内核标准教程(共计8--第5个)

    4.1 进程与线程的概念 129 4.1.1 程序与进程 129 4.1.2 进程与线程 129 4.2 进程描述符 131 4.2.1 进程标识符 132 4.2.2 进程的状态 132 4.2.3 进程上下文 134 4.2.4 当前进程 139 4.3 进程的组织...

    嵌入式Linux应用程序开发标准教程(第2版全)

    接着系统地讲解了嵌入式Linux的环境搭建,以及嵌入式Linux的I/O与文件系统的开发、进程控制开发、进程间通信开发、网络应用开发、基于中断的开发、设备驱动程序的开发以及嵌入式图形界面的开发等,并且还安排了丰富...

    深入分析Linux内核源码.chm

    1.1 GNU与Linux的成长 1.2 Linux的开发模式和运作机制 1.3走进Linux内核 1.4 分析Linux内核的意义 1.5 Linux内核结构 1.6 Linux内核源代码 1.7 Linux内核源代码分析工具 第二章 Linux运行的硬件基础 2.1 i386的...

    详解ARM Linux 2.4.x进程调度

    Linux2.4.x是一个基于非抢占式的多任务的分时操作系统,虽然在用户进程的调度上采用抢占式策略,但是而在内核还是采用了轮转的方法,如果有个内核态的线程恶性占有CPU不释放,那系统无法从中解脱出来,所以实时性并...

    线程和进程的区别及Python代码实例

    在面向线程设计的系统(如当代多数操作系统、Linux 2.6及更新的版本)中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。...

    linux C编程实战

     1.3 Linux的安装、启动与关闭   1.4 Linux的基本使用   1.4.1 Linux终端   1.4.2 Linux Shell   1.4.3 Linux的常用命令   1.5 Linux下程序的开发环境和开发过程   1.6 习题   第2章 C编程...

    论文研究-LINUX平台下基于EPOLL的FTP服务器设计与实现 .pdf

    LINUX平台下基于EPOLL的FTP服务器设计与实现,王亚昌,,网络服务器通常采用多进程、多线程并发机制或者是基于select/poll的I/O复用模型实现,传统的FTP服务器大都使用前者。本文针对Linux 2.6内�

    Linux高级程序设计

    本书以2.6内核的Linux操作系统为开发平台、GCC 4.0/GDB 6.3为开发调试环境,详细介绍了Linux下C语言开发环境、C语言开发工具、内存管理、ANSI C文件I/O管理、POSIX文件I/O管理、文件及目录管理、进程管理、 UNIX进程...

    Linux多线程服务端编程:使用muduo C++网络库

    4.9多线程与fork() . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 102 4.10多线程与signal . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 103 4.11Linux 新增系统调用的启示. ....

    操作系统课件

    中央处理器 2.2 中断技术 2.3 进程及其实现 2.4 线程及其实现 2.5 Linux进程和线程 2.6 Windows 2003进程和线程 2.7 处理器调度 2.8 处理器调度算法 2.9 Linux调度算法 2.10 Windows 2003调度算法

    一个进程池的服务器程序

    总的来说,思想是让子进程accept并处理请求,父进程通过子进程发来的信息控制请求数与子进程数之间的关系。 代码如下: 代码如下: #include #include #include #include #include #include #include #...

    LINUX高级程序设计(中文第二版)杨宗德 (1)

    本书以linux操作系统(内核为2.6版本)为开发平台、gcc 4.0/gdb 6.3为开发调试环境,详细介绍了linux系统下编程环境及编程工具、文件管理(文件类型、ansi以及posix标准下文件读写操作)、进程管理(创建、退出、执行、...

Global site tag (gtag.js) - Google Analytics