线程
https://www.cnblogs.com/ay-a/category/1114145.html
优秀随笔
2018年12月22日
12:57
因为进程同时控制资源和cpu调度,实现并法时创建起来和上下文切换很耗费时空资源,所以引入了进程的概念。
进程同时有独立地址空间和主存等,又是一个独立调用和分派的基本单位,所以限制了并发的规模度,为了解决这个问题,引入了线程的概念,操作系统可以增大并发度并减少系统多余开销。
线程分用户线程和内核线程:
用户线程对程序员来讲是可见的,而对内核来说是未知的。操作系统只会控制和管理内核进程。
内核线程:处于内核态的线程,负责系统调用,在内核空间执行创建调度和管理,时间片的分发以线程为单位,同进程内线程越多获得的时间片越多。
用户线程:用户创建的线程,内核了解线程的存在,内核只调用进程,进程时间片由所有线程均分,由用户线程库管理.线程维护由用户管理。
线程是CPU使用的基本单元
由线程ID,程序计数器,寄存器集合,栈组成
他和同一进程的其他线程共享代码,数据和其他操作系统资源。打开文件和信号。
传统重量级进程只有单个线程。
寄存器集合,栈和私有存储区域称为线程的上下文
ETHREAD,执行线程块 包括线程所属进程的指针,子程序的地址,也包括内核线程块的指针 KTHREAD 内核线程块 包括调度信息和同步信息。包括内核栈和TEB的指针 TEB 线程执行环境块 线程本地存储 | |
因为如果用户线程想要系统调用就必须进入内核状态,所以用户线程的系统调用用内核线程完成。内核线程和用户线程的对应方式有三种模型:
Many-to-One多个用户线程使用一个内核线程,实现不了并发调用
One-to-One多个用户线程和多个内核线程配对,这样可以实现并发,缺点对线程数目有要求,因为需要很多资源来满足该模型。
Many-to-Many 多个用户线程对应多个内核线程,这样可以实现并发,也可以减少线程的浪费。
两级模型:一些多对多,重要的线程可以多对一
信号处理
信号和中断类似,但信号是在用户态下进行的。具体区别不多赘述
信号去向
发送到信号所应用的线程
发送信号到进程内的所有线程
发送信号到进程内的某些固定线程
发送信号到特定线程
windows不明确提供对信号的支持,需要用异步过程调用来模拟,(指定一个函数当用户线程收到特定事件通知时调用)
线程池
Win32提供了线程池功能,床i就按一些空闲的线程,如果有任务就选用现有线程去执行。
QueueUserWorkItem
用线程池中的线程调用函数
三种主流线程库
Pthread
由POSIX标准制订为线程创建和同步指定的规范API。
头文件pthread.h
pthread_t tid;//线程
pthread_attr_t attr;//线程属性
pthread_attr_init(&attr);//用默认来初始化线程属性
pthread_create(&tid,&attr,void*(*p)(void*),void* arg);//创建线程,传入函数和参数
pthread_join(tid,NULL);//等待某个线程
pthread_exit(0);//结束本线程并返回0
Win32
头文件windows.h
HANDLE WINAPI CreateThread
java
java在windows上的县城库用Win32实现,linux和UNIX上的线程库由pthread实现
继承THread并重载run函数,或是实现Runnable接口实现run函数。
调用start方法启动线程
和进程的比较:
线程负责cpu调度,进程负责资源及其他
创建时间比进程短
终止时间比进程短
上下文切换时间比进程短
同进程内线程的通信不需要内核协助
响应度高:同时处理用户的多个操作
资源共享:多线程共享堆内存和资源,方便通信
经济:创建线程比创建进程需要的资源更少。无须重新分配资源
引入前:
资源分配单位(文件,设备,存储器),调度基本单元(分配),又称任务(Task)
引入后:
进程负责资源分配和调度线程,线程负责分配时间片
线程特定数据
所有线程都共享数据,但是如果线程想一些数据拥有自己的副本,就需要用~。
c++Thread类
detach方法,让线程分离,这样在线程运行完成后会自动释放,不detach就一定要join,
LWP轻量级进程(windows不支持)
一个LWP有一个内核线程支持。是内核线程的抽象。之前说的多对一或多对多或一对一都是说的LWP,LINUX特有
fork()和exec()的问题
由两种方式调用fork,一个复制所有线程,一个是只复制当前线程。
exec会用新的进程替换整个进程
如果fork后立即调用exec,那么只复制当前线程较为合适,不然应复制所有线程