
目录
[1. 线程本质](#1. 线程本质)
[2. 线程互斥](#2. 线程互斥)
[2.1 信号量](#2.1 信号量)
[2.2 认识锁的接口](#2.2 认识锁的接口)
[2.3 理解锁](#2.3 理解锁)
[3.1 条件变量](#3.1 条件变量)
1. 线程本质
在用户层,封装轻量级进程,形成原生线程库pthread库,是动态库也是ELF库,动态库需要加载到内存。线程的概念是在库中定义的,那在库中就一定有多个创建好的线程,库当然也要管理线程:先描述,再组织
bash
struct tcb <-- pthread_create
{
线程状态
线程id
线程独立的栈结构
线程栈大小
...
}

2. 线程互斥
先区分几组概念
临界资源:多线程执行流被保护的共享的资源就叫做临界资源
临界区;每个线程内部,访问临界资源的代码,叫做临界区
互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成
2.1 信号量
本质是一个计数器,用来表明临界资源中资源的数量。可以用电影院买票来理解,想访问临界资源都得先买票,进程访问临界资源,先申请信号量,本质是对资源的预定机制。信号量本身就是共享资源,信号量只有0和1两态的信号量,叫做二元信号量,也就是互斥
数据不一致现象
bash
int ticket=100;
void* Routine(void* args)
{
char* id=(char*)args;
while(1)
{
if(ticket>0)
{
usleep(1000);
printf("%s sells ticket:%d",s,id);
ticket--;
}
else break;
}
return nullptr;
}
可以看到票数减到负数
ticket全局资源没有加保护,就会产生并发问题,线程安全问题。需要加锁来解决
2.2 认识锁的接口
全局:pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER
局部:int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
申请锁,释放锁:int pthread_mutex_lock(pthread_mutex_t*mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
竞争申请锁,多线程都得先看到锁,锁本身就是临界资源!!申请锁的过程,必须是原子的
失败:阻塞挂起申请执行流
成功,继续向后运行,访问临界区代码,访问临界资源
锁提供的能力的本质:执行临界区代码由并行转换成为串行
对临界资源的保护:本质就是用锁,对临界区代码进行保护
可以想象成自习室

加锁之后,临界区代码是允许线程切换的。但是:因为我当前线程,并没有释放锁,我是持有锁被切换的,即便我不在!其他线程也得等我回来执行完代码,释放锁,其他线程才能展开锁的竞争,进入临界区
2.3 理解锁
1.硬件级实现:关闭时钟中断
2.软件级实现:为了实现互斥锁操作.大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单无的数据相交换
如果把一个变量的内容,交换到CPU寄存器内部,本质是:把该变量的内容,获取到当前执行流的硬件上下文中,当前CPU寄存器的硬件上下文(其实就是各个寄存器的内容)属于:进程/线程私有的!!!!!!我们用swap,exchange将内存中的变量,交换到CPU的寄存器中:本质是当前线程/进程,在获取锁,因为是交换,不是拷贝!!!,所以1只有一份!!,所以,谁申请到,谁持有锁!!
3.线程同步
锁的技术也带来了新的问题,如果一个线程高频的申请锁,没有做有效的动作,其他线程又申请不到就会产生线程饥饿问题。为了解决线程饥饿就需要制定新的方案:
1.不能立即申请第二次
2.外边的人,进行排队,退出的人,必须跑到队列的尾部,进行二次申请
在保证自习室安全的前提下,让所有的执行流,访问临界资源按照一定的顺序进行访问资源!!:
线程同步!!
3.1 条件变量
当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量
举个放苹果的例子:
接口
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t)*cond);
int pthread cond init(pthread cond t *restrict cond, const pthread condattr t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t*restrict mutex)
在指定的条件变量下等待
int pthread_cond_broadcast(pthread_cond_t *cond);唤醒在指定条件变量下等待的所有的线程
int pthread_cond_signal(pthread_cond_t *cond);唤醒在该条件变量下等待的一个线程
点个关注不迷路