Linux多线程

Linux多线程

1. 线程?

线程是一个进程内部的控制序列。线程共享进程数据,但线程也拥有自己私有的上下文数据、私有栈结构。是程序执行的最小单位。

2. Linux中的线程

Linux中的线程是用进程模拟的。在Linux中,操作系统没有专门的结构来管理线程,而是用给线程分配一个PCB(更准确地说应该叫TCB)。我们知道,Linux在创建进程时做了有如下工作:
1. 分配一个进程描述符,新建PCB
2. 复制父进程的环境
3. 分配系统资源
4. 复制父进程的代码
5. 置成就绪状态,放入就绪队列

而在创建线程时,首先新建一个“PCB”,然后从进程所拥有的资源中为线程分配它运行时必要的一些资源。下面以图示来进行说明:
线程
一个进程拥有自己的PCB,PCB中包含了虚拟地址空间的信息,而虚拟地址空间通过页表完成对物理内存的映射。当该进程创建出线程后,便从进程的PCB中拷贝一份形成TCB,因此TCB中的虚拟地址空间的信息是不变的。所以进程和线程共享一块虚拟地址空间。正是因为如此,如果定义一个函数,那么该函数保存在虚拟地址空间的代码段,在各线程中都可以调用;如果定义一个全局变量,那么在各线程中都可以访问到。由于线程都是从进程得来的,因此没有“父线程子线程”一说,只有“新线程”与“旧线程”,即:一个进程下的所有线程都是平等地位的。

总的而言,线程共享的资源有:
1. 定义的函数
2. 全局变量
3. 文件描述符
4. 函数指针数组handler
5. 当前工作目录
6. 用户id和组id

线程私有的资源有:
1. 线程id
2. 调度优先级
3. 位图block
4. 上下文数据
5. 私有栈结构

3. 线程的注意事项

第一点,线程之所以被引入,是为了弥补计算机I\O时CPU处于等待状态而无法充分利用CPU的缺点。
事实上,不管是线程还是进程,任意时刻绝大部分都是睡眠的,即现代计算机大多数是IO密集型,涉及IO必然要等待,进程调度下,进程一旦等待,必然要切换另一个进程执行,而在线程调度下,一个线程等待,可以调度另一个线程运行。如果一个线程阻塞,在没有同步关系的情况下完全可以调度其他的线程运行,粒度更小,相当于间隙更小,这样程序运行势必更快。但是这只适用于I\O密集型应用。如果是计算密集型应用,若不是多处理机,则多线程就没有意义。

第二点,对于一个进程而言,由它产生的线程是共享相当一部分资源的。若是在运行过程中某个线程发生崩溃,则会导致共享的资源发生不可预知的问题,发生连锁反应,进而导致整个进程发生崩溃。而被引发崩溃的进程,则由它的父进程进行回收。

4. 线程ID

在Linux中,目前线程实现是Native POSIX Thread Libaray,简称NPTL。在这种实现下,线程又被成为轻量级线程,每一个用户态的线程,在内核中对对应一个调度实体,也拥有自己的进程描述符(task_struct结构体)。

没有线程之前,一个进程对应内核中的一个进程ID。但是引入线程概念之后,情况发生了变化,一个用户进程下管辖N个用户态线程,每个线程作为一个独立的调度实体在内核中有自己的进程描述符,进程和内核的关系变成了1:N的关系。

为了更好地将线程组织起来,Linux内核引入了线程组的概念。

多线程的进程,被称为线程组,线程组内的每一个线程在内核中都存在一个进程描述符与之对应。进程描述符结构体中的pid,表面上看是对应着进程ID,实际上它对应的是线程ID。进程描述符中的tgid,含义是Thread Group ID, 该值对应的是用户层面的进程ID。

线程组内的第一个线程,在用户态被称为主线程,在内核中被称为group leader,内核在创建第一个线程时,会将线程组ID的值设置成第一个线程的线程ID,group_leader指针则指向自身,即指向主线程的进程描述符。所以线程组内存在一个线程,它的ID等于进程ID,而该线程即为线程组的主线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值