什么是线程
线程是OS调度的基本单位
其实在Linux环境下,线程可以看做是轻量级线程
Linux的线程本质仍然是进程。Linux先有进程后有线程,当创建了一个进程时,系统给他分配一段4G的虚拟内存,并在其内生成进程的PCB,当他调用相关函数创建一个线程时,会为新的线程生成一个PCB也存放在当前的4G虚拟内存中,而原来的进程也沦为一个线程。
Linux的线程本质仍然是进程。Linux先有进程后有线程,当创建了一个进程时,系统给他分配一段4G的虚拟内存,并在其内生成进程的PCB,当他调用相关函数创建一个线程时,会为新的线程生成一个PCB也存放在当前的4G虚拟内存中,而原来的进程也沦为一个线程。
为什么说Linux下,为什么说在Linux线程本质还是进程?
在其他的操作系统中,它认为进程和线程是不一样的,进程用PCB描述,线程用TCP描述
但是在Linux中认为:没有进程,没有线程在概念上的区分,只有一个,叫做执行流;Linux的线程是用进程的PCB模拟的
在Linux上没有单独设计TCP,所以它没有真正意义上的TCP,而是复用了PCB来模拟表示对应的线程(执行流)的概念
看图
这样设计的好处是什么呢?
- 不用单独设计TCP
- 不用维护TCP和PCB之间的关系
- 不用在单独编写调度算法了
- 而且在CPU看到所有task_struct都是一个执行流(线程)
线程优点
- 创建一个新线程的代价要比创建一个新进程小得多 (只需要创建PCB,不需要创建虚拟地址空间和页表)
- 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多(只需要切换PCB,不需要切换虚拟地址空间,页表)
- 线程占用的资源要比进程少很多
- 能充分利用多处理器的可并行数量
- 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
- 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
- I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
线程缺点
- 线程不具有独立性,线程是进程的执行分支,所以如果线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随着退出
进程和线程
- 进程的OS分配资源的基本单位(像虚拟地址空间啊,页表啊)
- 线程是OS调度的基本单位
- 线程虽然共享进程的数据,但是也拥有自己的一部分数据
线程ID
线程独立栈
调度优先级
errno
信号屏蔽字 - 各线程共享一下进程资源和环境
文件描述符
每种信号的处理方式(SIG_IGN,SIG_DFL或者自定义信号处理函数)
当前工作目录
用户id和组Id
线程独立栈
linux没有真正意义上的线程,所以我们创建线程的接口不是系统接口,但是linux上有一个原生的线程库,是应用层开发出来的,它是动态库.
我们来看看创建线程的接口
功能:创建一个新的线程
原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(*start_routine)(void*), void *arg);
参数
thread:返回线程ID
attr:设置线程的属性,attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码
看完接口,我们来解决下面的问题
pthread_t是什么,怎么理解线程栈?
我们知道线程是一个独立的执行流,所以线程一定会在自己的运行过程中,产生临时数据(调用函数,定义局部变量等);所以线程一定需要有自己的独立栈结构。
那pthred_t到底是什么呢?我们来看图
从图中可以看出,其实pthread_t就是地址,具体来说,pthread_t保存的是我们对应用户级线程的控制结构体的起始地址。
其实线程的全部实现,并没有体现在OS内,而是OS提供执行流,具体的线程结构由库来进行管理。
库可以创建多个线程,那么库如何管理线程呢?(OS只提供轻量级进程,用户来的是线程,那libpthread.so这个库就帮我们利用OS的轻量级进程去给我们创建线程,所以线程的概念是在库这一层的)(libphread.so就是线程库)
所以库要用一个数据结构,其实 就是结构体thread_info进行管理
struct thread_info
{
pthread_t tid;
void *stack;//私有栈
....
}
补充:主线程的独立栈结构,用的就是地址空间中的栈区;新线程用的栈结构,用的是库中提供的栈结构。