线程 总结

一、线程的概念

线程是进程的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中可以有多个线程

多个线程共享同一个进程的资源,每个线程参与操作系统的统一调度

可以简单理解: 进程 = 进程资源 + 主线程 + 子线程+......

进程与线程的区别:

1、线程包含于进程,多个进程拥有独立的内存空间

2、线程间通讯方式简单,进程间通讯方式复杂

并发操作,线程比进程更节约资源

联系紧密的任务在并发时优先选择多线程,如果任务之间比较独立,在并发时建议选择多进程。

二、线程的资源

共享进程的资源
        同一块地址空间
        文件描述符表
        每种信号的处理方式(如:SIG_DFL,SIG_IGN或者自定义的信号优先级)
        当前工作目录
        用户id和组id

独立的资源
        线程栈
        每个线程都有私有的上下文信息。
        线程ID
        寄存器的值
        errno变量
        信号屏蔽字以及调度优先级

三、线程的命令

 pidstat命令可查看对应进程的线程

 top命令 top -H -p pid

可查看某一进程下的线程(需要知道进程的pid)

ps - T 可以查看某个进程下的所有线程

四、创建线程

1、创建线程使用 pthread_create 函数

        一旦子线程创建成功,则会被独立调度执行,并且与其他线程并发执行
        在编译时需要链接 -lpthread

2、线程退出使用 pthread_exit 函数

        当主线程调用pthread_exit函数时,

3、进程不会结束,也不会导致其他子线程退出
        任何线程调用exit函数会让进程结束

4、线程等待调用 pthread_join函数,会阻塞调用线程

5、线程分为可结合的与可分离的
        可结合
                可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。
                线程创建的默认状态为可结合的,可以由其他线程调用 pthread_join函数等待子线程退出并释放相关资源
        可分离
                不能被其他线程回收或者杀死的,该线程的资源在它终止时由系统来释放。

线程分离调用 pthread_detach 函数

五、创建多个线程

线程一般由主线程统一创建,并等待释放资源或分离线程,不要递归创建

        1. 多个线程如果任务相同,则可以使用同一个线程执行函数
        2. 多个线程如果任务不同,则可以使用不同的线程执行函数

六、线程间通信

1、主线程向子线程传递参数

通过 pthread_create 函数的第4个参数 arg 进行传递


2、子线程给主线程传递参数
子线程给主线程传参的方式如下:
        在子线程将需要返回的值存储在 pthread_exit 函数中的 retval 参数中
        在主线程中通过 pthread_join 函数的第2个参数 retval 得到返回, pthread_join 函数会将线程的1返回值(指针)保存到 retval 中

七、线程互斥锁

1、线程的主要优势在于能够通过全局变量来共享信息,不过这种便捷的共享是有代价的:
        必须确保多个线程不会同时修改同一变量
        某一线程不会读取正由其他线程修改的变量,实际就是 不能让两个线程同时对临界区进行访问
        线程互斥锁则可以用于解决多线程资源竞争问题

2、 线程互斥锁工作机制
        当线程A获得锁,另外一个线程B在获得锁时则会阻塞,直到线程A释放锁,线程B才会获得锁。
2. 线程互斥锁工作原理
        本质上是一个pthread_mutex_t类型的变量,假设名为 v
        当 v = 1,则表示当前临界资源可以竞争访问 ,得到互斥锁的线程则可以访问,此时 v = 0
        当 v = 0,则表示临界资源正在被某个线程访问,其他线程则需要等待
3. 线程互斥锁的特点
        互斥锁是一个 pthread_mutex_t类型的变量,就代表一个互斥锁
        如果两个线程访问的是同一个 pthread_mutex_t 变量,那么它们访问了同一个互斥锁
        对应的变量定义在 pthreadtypes.h 头文件中,是一个共用体中包含一个结构体

八、线程互斥锁的初始化

1、静态初始化

定义 pthread_mutex_t 类型的变量,然后对其初始化为 PTHREAD_MUTEX_INITIALIZER
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER

2、动态初始化

动态初始化主要涉及两个函数 pthread_mutex_init 函数 与 pthread_mutex_destroy 函数

3、

线程互斥锁的操作主要分为 获取锁(lock) 与 释放锁(unlock)
获取锁的函数:pthread_mutex_lock

释放锁的函数:pthread_mutex_unlock

八、线程同步

一、线程同步的概念
        线程同步:是指在互斥的基础上,通过其它机制实现访问者对 资源的有序访问。
        条件变量:线程库提供的专门针对线程同步的机制
        线程同步比较典型的应用场合就是 生产者与消费者
二、生产者与消费者模型原理
     1. 在这个模型中,包括生产者线程与消费者线程。通过线程来模拟多个线程同步的过程
 2. 在这个模型中,需要以下组件
        仓库 : 用于存储产品,一般作为共享资源
        生产者线程 : 用于生产产品
        消费者线程 : 用于消费产品
3. 原理
        当仓库没有产品时,则消费者线程需要等待,直到有产品时才能消费
        当仓库已经装满产品时,则生产者线程需要等待,直到消费者线程消费产品之后

九、条件变量

条件变量的本质为 pthread_cond_t 类型的变量,其他线程可以阻塞在这个条件变量上,或者唤醒阻塞在这个条件变量上的线程

条件变量的初始化分为静态初始化与动态初始化
1. 静态初始化

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2. 动态初始化
pthread_cond_init 函数

pthread_cond_destroy函数

3、条件变量的阻塞与唤醒

step 1 :消费者线程判断消费条件是否满足(仓库是否有产品),如果有产品则可以消费,然后解锁
step 2 :当条件满足时(仓库产品数量为0),则调用 pthread_cond_wait 函数,这个函数具体做的事
情如下:
        在线程睡眠之前,对互斥锁解锁
        让线程进入到睡眠状态
        等待条件变量收到信号时,该函数重新竞争锁,并获取锁
step 3 :重新判断条件是否满足,如果满足,则继续调用 pthread_cond_wait 函数
step 4 :唤醒后,从 pthread_cond_wait 返回,条件不满足,则正常消费产品
step 5 :释放锁,整个过程结束

4、 pthread_cond_wait 

作用: 阻塞线程,等待唤醒

条件变量需要与互斥锁结合使用,先获得锁才能进行条件变量的操作
调用函数后会释放锁,并阻塞线程
一旦线程唤醒,需要重新竞争锁,重新获得锁之后,pthread_cond_wait 函数返回

5、 pthread_cond_signal和pthread_cond_broadcast

pthread_cond_signal 函数主要适用等待线程都在执行完全相同的任务
pthread_cond_broadcast 函数主要适用等待线程都执行不相同的任务
条件变量并不保存状态信息,只是传递应用程序状态信息的一种通讯机制,发送信号时若无任何线
程在等待该条件变量,则会被忽略
条件变量代表是一个通讯机制,用于传递通知与等待通知,用户可以设定条件来发送或者等待通知

6、 为什么条件变量需要与互斥锁结合起来使用?
答:防止在调用 pthread_cond_wait 函数等待一个条件变量收到唤醒信号,另外一个线程发送信号在第一个线程实际等待它之前,也就是说线程还没有完全进入到睡眠状态,其他线程发送唤醒信号

7、在判断条件时,为什么需要使用 while(number == 0),而不是 if()
答:防止虚假唤醒。
能够唤醒的情况如下:
        被信号唤醒,并非由条件满足而唤醒
        条件变量状态改变时,一次唤醒多个线程,但是被其他线程先消费完产品,等到当前线程执行时,条件已经不满足

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值