Linux:线程同步与互斥
目录
线程互斥
锁
初始化
销毁
加锁
解锁
线程同步
条件变量
初始化
销毁
等待条件满足
唤醒等待
pthread_cond_signal
pthread_cond_broadcast
生产者消费者模型
3种关系
2种角色
1个交易场所
POSIX信号量
初始化
销毁
等待
发布
线程互斥
互斥相关概念
临界资源:多线程执行流共享的资源就叫做临界资源。
临界区:每个线程内部,访问临界资源的代码,就叫做临界区。
互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。
原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。
多线程并发操作一些共享变量会有一些问题
例如变量++,--的操作就不能多线程并发访问
++,--的操作在汇编中需要分为3步
1.将变量从内存加载到寄存器中
2.更新寄存器里面的值,执行+1(-1)操作
3.将新值从寄存器写回会变量的内存地址中
因为寄存器用的都是同一个,在并发访问时就会出现问题
要解决以上问题,需要做到三点:
1.代码必须要有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。
2.如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临界区。
3.如果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区。
想要做到这三点,我们可以使用一把锁。Linux上提供的这把锁叫互斥量
锁
pthread_mutex_t
这是一个互斥锁的类型,定义在POSIX线程库中。
互斥锁用于保护共享资源的访问,确保在多线程环境中,同一时间只有一个线程可以访问该资源,从而避免数据竞争和不一致的问题。
我们可以用这个类型来定义一个锁变量,并初始化它
初始化
方法1:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
PTHREAD_MUTEX_INITIALIZER这是一个宏,用于初始化静态分配的互斥锁
方法2:
#include <pthread.h>int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutexattr);
mutex:指向要初始化的互斥锁对象的指针
mutexattr:指向互斥锁属性对象的指针。如果为NULL,则使用默认属性(一般情况使用NULL即可)
返回值:
成功:返回0
失败:返回错误码
销毁
锁也需要像malloc,new出来的动态内存一样需要我们手动释放,但并不是所有情况都需要手动释放的
当使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量不需要销毁
#include <pthread.h>int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex:指向要销毁的互斥锁对象的指针
返回值:
成功:返回0
失败:返回错误码
加锁
我们可以对一段代码区进行加锁,这样就只能有单执行流访问一段代码了
#include <pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_lock用于锁定一个互斥锁
mutex:指向要锁定的互斥锁对象的指针
返回值:
成功:返回0
失败:返回错误码
解锁
有加锁当然也会有解锁,加锁和解锁之间的区域就是我们拥有锁的区域
#include <pthread.h>int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_unlock用于解锁一个互斥锁
mutex:指向要解锁的互斥锁对象的指针
返回值:
成功:返回0
失败:返回错误码
线程同步
条件变量
条件变量是一种在多线程编程中用于线程同步的机制,它允许线程在某些条件不满足时进入等待状态,直到条件满足时才被唤醒继续执行。
初始化
初始化一个条件变量。
int pthread_cond_init(pthread_cond_t *cond
, const pthread_condattr_t *cond_attr);
cond:指向条件变量的指针,需要初始化的条件变量。
cond_attr: 指向条件变量属性的指针。如果为NULL,则使用默认属性。
返回值:
成功:返回0
失败:返回错误码
销毁
销毁一个条件变量,释放相关资源。
int pthread_cond_destroy(pthread_cond_t *cond);
cond:指向条件变量的指针,需要销毁的条件变量。
返回值:
成功:返回0
失败:返回错误码
等待条件满足
使线程进入等待状态,直到条件变量被通知。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
cond:指向条件变量的指针。
mutex:指向互斥锁的指针,该互斥锁必须已经被当前线程锁定。
当调用pthread_cond_wait的时候,线程会释放mutex,并进入等待状态
当条件变量被通知时,线程会被唤醒,并重新尝试获取mutex
唤醒等待
pthread_cond_signal
通知一个等待条件变量的线程。
int pthread_cond_signal(pthread_cond_t *cond);
cond:指向条件变量的指针。
返回值:
成功:返回0
失败:返回错误码
pthread_cond_broadcast
通知所有等待条件变量的线程。
int pthread_cond_broadcast(pthread_cond_t *cond);
cond:指向条件变量的指针。
返回值:
成功:返回0
失败:返回错误码
生产者消费者模型
3种关系
生产者之间:竞争关系,互斥关系
消费者之间:竞争关系,互斥关系
生产者和消费者之间:竞争关系,互斥关系,同步关系
2种角色
生产者角色和消费者角色
1个交易场所
以特定结构构成的内存空间
POSIX信号量
初始化
初始化一个信号量。
#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);
sem:指向信号量的指针。
pshared:指定信号量是否可以在不同进程之间共享。为0:信号量仅在当前进程内的线程之间共享。非0:信号量可以在不同进程之间共享(需要映射到共享内存)
value:信号量的初始值。
返回值:
成功:返回0
失败:返回错误码
销毁
销毁一个信号量,释放相关资源。
#include <semaphore.h>int sem_destroy(sem_t *sem);
sem:指向信号量的指针。
返回值:
成功:返回0
失败:返回错误码
等待
使线程进入等待状态,直到信号量的值大于零,然后将信号量的值减一。
#include <semaphore.h>int sem_wait(sem_t *sem);
sem:指向信号量的指针。
返回值:
成功:返回0
失败:返回错误码
发布
将信号量的值加一,通知等待信号量的线程。
#include <semaphore.h>int sem_post(sem_t *sem);
sem:指向信号量的指针。
返回值:
成功:返回0
失败:返回错误码
完