4月「掘金·日新计划」第8天
一、概念
总的来说,线程的优点缺点,都是来自内存地址共享 健壮性,切换效率,节俭,通信
1.1、线程是什么
- 一个进程最少有一个线程
- 同一时刻做多件事情
- 同一进程的多个线程共享进程地址空间
1.2、进程线程区别
-
健壮性(进程更健壮)
- 进程:有独立地址空间,崩溃不会影响其他
- 线程:没有单独地址空间,崩溃等于进程崩溃
-
效率(线程高)
- 进程切换,资源消耗大,效率差
- 对要求同时并共享变量,并发操作,只能线程
1.3、使用线程的理由优点
-
节俭的多任务操作方式
- 共享进程地址空间,进程是独立地址空间(耗内存)
- 切换效率时间:线程>进程,开销进程远远大于线程(大约30倍)
-
通信机制方便
- 因为内存共享
1.4、选择多进程还是多线程
内存,数据通信,线程安全(竞争死锁问题)
1.5、多线程开发api
-
包含3点:线程,互斥锁,条件
-
线程
-
创建,退出,等待
-
可以传递参数进入线程(也可以全局变量不需要传递,直接使用)
传结构体指针数组,要强转为二级指针承接,然后p[0]使用
-
线程退出也可以传递数据回来,需要加static,不然会被释放
-
等待,会阻塞等待线程退出
-
-
互斥量(mutex)
-
创建,销毁,加锁,解锁
-
拿到锁的线程加锁,剩下线程拿不到锁阻塞等待锁释放
-
保证临界资源不在同一时间被修改访问
-
应该注意:
- 尽量保证锁的粒度, 越小越好。(访问共享数据前,加锁。访问结束立即解锁。)
-
线程同步的四种方式:互斥锁,条件变量,读写锁,信号量
-
信号量:允许多个线程进入临界区,信号量允许被调度和睡眠,锁的竞争者会转入睡眠(信号量不能用于中断上下文,只能进程上下文。自旋锁可以中断上下文)
-
自旋锁:持有者临界区不允许被抢占,不允许调度和睡眠
-
读写自旋锁:允许多个读获得读锁,1个写获得写锁,读是共享锁,写是互斥锁
-
顺序锁:读写锁会导致写锁等待,顺序锁赋予写锁高优先权(写持有锁,读者就要多次执行临界区代码)
-
读写锁:与互斥量类似,但读写锁允许更高的并行性。其特性为:写独占,读共享。读锁、写锁并行阻塞,写锁优先级高
-
-
条件
-
创建,销毁,触发,广播,等待
-
触发:向一个线程发消息。广播:向多个发消息
-
宏初始化(静态初始化),函数是动态初始化
-
同步,就是按照预定的先后顺序运行,一个锁
按照某种特定的顺序访问临界资源,从而有效避免饥饿问题
-
1.6、死锁
-
有几种原因
- 线程试图对同一个互斥量 A 加锁两次
- 线程 1 拥有 A 锁,请求获得 B 锁;线程 2 拥有 B 锁,请求获得 A 锁
- 加锁之后忘记解锁
-
造成2个线程都不能继续运行下去
1.7、生产者消费者
-
概念
- 一个进程里面有多个线程,分别扮演消费者和生产者两类
- 其中生产者为消费者提供任务,消费者去拿到任务并且执行任务。
- 而他们之间的“交易场所”为内存块,即全局变量
- 一个放,一个拿
-
生产者消费者模型优点
-
解耦
因为多了一个缓冲区,所以生产者和消费者并不直接相互调用
-
支持并发
生产者和消费者就是两个独立的并发体
-
支持忙闲不均
-
效率高
-