1. 什么是线程
2. 线程和进程的关系
3. 线程的工作原理
4.线程和进程实现并发任务的优、缺
5. 线程控制
- 什么是线程
在传统的操作系统中,进程就是一个pcb(进行运行中的程序的描述信息),控制程序的运行,但是在linux下没有为线程设计一个pcb来控制线程的运行,线程此时就是以进程pcb模拟实现的,也就是说,线程在linux下pcb实际上是一个线程,在linux下线程以进程pcb模拟实现,所以线程也叫轻量级进程。
linux下的进程实际上是一个线程组,包含一个或者多个线程 - 线程和进程之间的关系
- 因为cpu调度程序运行时调度pcb,因此线程是cpu调度基本单位
- 因为一个程序运行起来就会分配大量的资源给线程组,因此进程是资源分配的基本单位
- 线程的工作原理
我们都知道在进程中vfork()创建子进程与父进程公用同一个虚拟地址空间,因此我们的进程不能同时的去运行,那么线程公用同一个虚拟地址空间如何做到我们同时运行了?
其实这个问题我们可以从问题上来解决,思考为什么vfork()不能同时运行呢,因为他是共用的同一个虚拟地址空间,但是我们在线程同可以将我们的进程需要的地址空间进行公有,但是我们线程自己独立使用的时候就需要私有化。
多线程中线程与线程之间独有的数据
- 栈区
在虚拟地址空间中的栈区,在前面的知识中已经讲解了 - 寄存器
寄存器是线程独有的数据,也成为线程的上下文,主要是为了反映 了上次运行时寄存器的状态,这部分应该是线程独有的 - errno
错误码,独有数据,假设我们在一个线程中出现一个错误的时候我们的在其他线程中也会出现此errno,所以我们需要errno独有 - 信号屏蔽字
在每个线程中可能在代码中的逻辑会出现不一样的信号屏蔽集 - 线程IO
文件描述符,因为在一个线程中打开的文件在其他线程中应该是不能被使用的,所以我们的线程IO应该是独有的。
同一个进程的线程共享的数据 - 数据段和代码段
- 文件描述符表
- 信号处理方式
- 用户ID,组ID
- 当前的工作路径(不一定是程序路径)
- 调度优先级
- 线程和进程实现并发任务的优、缺。
在多线程和多进程中我们都可以完成并发任务,但是哪一个更好呢?
其实两者是各有各的好处
线程实现并发任务的优点
- 线程通信更方便
- 线程的创建、销毁成本更低
- 同一个进程间的线程调度成本更低
- 执行粒度更加细致(就是我们线程是最小的执行单位,一个进程是由一个或者多个线程组成的)
线程实现并发任务的缺点 - 缺乏访问控制,健壮性低(一些系统调用和异常针对整个进程产生的效果)
上述都是线程实现并发的优缺点(对应的就是我们进程的缺优点)
两者共同的优缺点:
共同的缺点:
重点概念:
cpu密集程度:程序中都是大量的运行操作(需要cpu计算的多)
IO密集程序:程序中都是大量的IO操作
- 线程控制
操作系统没有提供线程控制的接口,使用的时候是系统调用接口,在内核中有程序去创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
pthread_t* thread:是传出参数,用来获得我们的线程id
const phread_attr_t* attr:设置线程的属性
void*(start_routine)(void):是我们的线程入口函数
void* arg:是线程传递的参数
返回值:成功返回0,失败返回errno
理解线程id:每一个线程都是一个pcb,task_struct都有一个pid,但是用户使用ps命令的时候查看线程缺只有一个线程,也就是只有一个进程的进程pid
但是在task_struct中含有LWP,PID,TID,其中LWP是task_strcut指向的pid,就是我们的轻量级进程id,PID是task_struct中的tgid,也就是线程组中的中线程pid,就是我们常说的进程id。我们的线程也是含有线程信息的,在共享内存中有一块内存存储的描述信息,就是栈和数据等等,TID就是我们描述信息的内存首地址,也就是我们的线程id(pthread_t).
- 线程终止
线程终止就是线程在此程序中退出,其中退出的方式包含了主动和被动退出,
主动退出:
- return退出,但是在线程入库函数中和主线程中是不一样的,在main中return是退出整个进程,在线程入库函数中是退出我们的该线程
#include <pthread.h>
void pthread_exit(void *retval);
Compile and link with -pthread.
retval:线程退出返回值
注意:线程退出也会形成我们的僵尸线程,主线程退出进程并不会退出,因为线程退出也要保存自己的退出返回值,
被动退出
#include <pthread.h>
int pthread_cancel(pthread_t thread);
Compile and link with -pthread.
这是退出我们指定的线程
thread_t thrad:就是我们制定的线程号
- 线程等待
线程等待:获取指定退出线程的返回值,并且允许操作系统回收线程资源
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
Compile and link with -pthread.
一个线程启动之后,默认有一个属性是线程joinable状态,处于joinable状态的线程退出时,不会自动释放资源,需要被等待,
在线程等待的时候就是回收我们线程并且获取退出原因,但是此时线程必须是处于joinable状态
pthread_t thread:回收的线程
void** retval:线程退出返回值
返回值:成功返回0,失败返回errno
- 线程分离
分离一个线程,在线程退出后系统将自动回收资源,被分离的线程无法被等待,若使用pthread_join进行回收直接报错返回,设置线程分离将从joinable状态变为detach状态
#include <pthread.h>
int pthread_detach(pthread_t thread);
Compile and link with -pthread.
pthread_t thread:被设置的线程id
被设置后线程处于EINVAL状态,这个状态就是线程不能被等待,或者已经被其他线程分离。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)