day27 同步互斥

同步互斥

线程资源是共享的,此时会出现多个线程对全局变量的访问,导致数据错误,以此引入同步互斥

临界资源 :多个线程抢夺的资源(全局变量,文件,数据库,内核资源)

临界区 :访问临界资源的代码

互斥 :同一时间内只允许一个线程访问临界资源(共享资源)

同步 :在互斥的基础上保证访问者的顺序

解决同步互斥问题:互斥锁,信号量,条件变量

互斥锁

概念

对于要访问临界资源的线程做上锁操作,如果上锁成功,则访问成功,如果上锁失败,则阻塞并等待互斥锁解锁再解除阻塞,再执行

速记

|------------------------|------|---------------|----------|
| 函数 | 功能 | 参数 | 返回值 |
| pthread_mutex_init | 初始化 | &mutex, NULL | 永0 |
| pthread_mutex_lock | 上锁 | &mutex | 成功0,失败非0 |
| pthread_mutex_unlock | 解锁 | &mutex | 成功0,失败非0 |
| pthread_mutext_destroy | 销毁锁 | &mutex | 成功0,失败非0 |
| pthread_mutex_trylock | 尝试上锁 | &mutex | 成功0,失败非0 |

相关函数

pthread_mutex_init

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

功能:初始化进程锁

定义方式:推荐第二个,我懒 ,可定义为全局

1.int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

2.pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;

参数:pthread_mutex_t *mutex 指向内存中mutex锁的地址的指针

const pthread_mutexattr_t *mutexattr 互斥锁属性 快速(默认),递归,错误检错锁

默认NULL

返回值:永为0

pthread_mutex_lock

int pthread_mutex_lock(pthread_mutex_t *mutex);

功能:上锁,如果锁资源被占用,阻塞等待,直到锁资源被释放,解除阻塞上锁成功

参数: pthread_mutex_t *mutex 指向内存中mutex锁的地址的指针

返回值:成功返回0,失败返回非0

pthread_mutex_unlock

int pthread_mutex_unlock(pthread_mutex_t *mutex);

功能:解锁,释放锁资源

参数: pthread_mutex_t *mutex 指向内存中mutex锁的地址的指针

返回值:成功返回0,失败返回非0

pthread_mutext_destroy

int pthread_mutex_destroy(pthread_mutex_t *mutex);

功能:销毁锁资源

参数: pthread_mutex_t *mutex 指向内存中mutex锁的地址的指针

返回值:成功返回0,失败返回非0

pthread_mutex_trylock

int pthread_mutex_trylock(pthread_mutex_t *mutex);

功能:尝试上锁,锁资源被占用了不会阻塞,报错EBUSY

参数: pthread_mutex_t *mutex 指向内存中mutex锁的地址的指针

返回值:成功返回0,失败返回非0

死锁

1.重复上同一把锁

2.锁资源没有释放,线程异常退出

3.线程重复上多把锁

信号量

对于要访问临界资源的线程都做申请信号的操作

|--------|--------------------------|
| 信号量大于0 | 申请成功,信号量-1 释放成功,信号量+1 |
| 等于0 | 申请失败,处于阻塞态,直到信号量大于0,解除阻塞 |

互斥锁:称为二值信号量(0,1)

解决问题:一个生产者少量消费者

P操作:申请 信号量-1

V操作:释放 信号量+1

速记

#include <semaphore.h>

|--------------|-------|---------------|----------------------|
| 函数 | 功能 | 参数 | 返回值 |
| sem_init | 初始化 | &sem,0,value | 成功返回0,失败返回-1,更新errno |
| sem_wait | 申请P | &sem | 同上 |
| sem_post | 释放V | &sem | 同上 |
| sem_destroy | 销毁 | &sem | 同上 |
| sem_getvalue | 获取信号量 | &sem,&sval | 同上 |

Link with -pthread.

相关函数

sem_init

int sem_init(sem_t *sem, int pshared, unsigned int value);

功能:初始化的信号量

参数: sem_t *sem:该指针指向的内存中存储信号量

int pshared: 0:表示线程共享 非0:表示进程共享

unsigned int value:用于信号量的初始化,允许多少个线程同时访问临界资源

返回值: 成功返回0,失败返回-1,跟新errno

sem_wait 申请 P -1

int sem_wait(sem_t *sem);

功能:申请信号量 -1 大于0,成功,等于0阻塞,直到大于0解除

参数: sem_t *sem:该指针指向的内存中存储信号量

返回值: 成功返回-,失败返回-1,根新errno

sem_post 释放 V +1

int sem_post(sem_t *sem);

功能:释放信号量 +1

参数: sem_t *sem:该指针指向的内存中存储信号量

返回值: 成功返回-,失败返回-1,根新errno

sem_destroy

int sem_destroy(sem_t *sem);

功能:销毁信号量

参数: sem_t *sem:该指针指向的内存中存储信号量

返回值: 成功返回-,失败返回-1,根新errno

sem_getvalue

int sem_getvalue(sem_t *sem, int *sval);

功能:获取信号量的值

参数: sem_t *sem:该指针指向的内存中存储信号量

int *sval: 该指针指向的内存中存储信号量的值

返回值: 成功返回-,失败返回-1,根新errno

条件变量

对于不访问临界资源的线程休眠,并设置一个唤醒条件(条件变量),如果该线程需要访问临界资源时,需要通过其他线程唤醒该线程

速记

|------------------------|----------|----------------|------|
| 函数 | 功能 | 参数 | 返回值 |
| pthread_cond_init | 初始化 | &cond,NULL | 0,非0 |
| pthread_cond_wait | 进程塞入等待队列 | &cond,&mutex | 同上 |
| pthread_cond_siganl | 唤醒队列第一个 | &cond | 同上 |
| pthread_cond_broadcast | 唤醒整个队列 | &cond | 同上 |
| pthread_cond_destroy | 销毁 | &cond | 同上 |

相关函数

pthread_cond_init

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);

功能:初始化条件变量

定义方式:推荐第二个,我懒 ,可定义为全局

1.int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);

2.pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

参数: pthread_cond_t *cond:该指针指向的内存中存储条件变量

pthread_condattr_t *cond_attr:条件变量属性

NULL:默认属性

返回值:成功0,失败非0

pthread_cond_wait

int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);

使用流程:

1.上锁pthread_muext_lock()

2.解锁,休眠 pthread_cond_wait()//解锁,休眠 ,上锁(如果被其他线程唤醒后 重新尝试上锁,如果上锁成功,则唤醒成功 如果上锁失败,则唤醒失败)

3.运行

4.解锁

参数: pthread_cond_t *cond:该指针指向的内存中存储条件变量

pthread_mutex_t *mutex:互斥锁

返回值:成功返回0,失败返回非0


条件变量为什么使用互斥锁:

当多核CPU时,同一时间执行多个线程,且同时调用pthread_cond_wait函数,同时把多个线程存到 休眠队列中,此时这个休眠队列就是多个线程需要抢夺的临界资源,解决互斥问题,需要引入互斥锁 哪个县城抢夺到了互斥锁,就把哪个县城存到休眠队列中,存储以后解锁,其他线程在存储袋休眠队列即可

pthread_cond_siganl

int pthread_cond_signal(pthread_cond_t *cond);

功能:唤醒休眠队列的第一个线程

参数: pthread_cond_t *cond:该指针指向的内存中存储条件变量

返回值:成功返回0,失败返回非0

pthread_cond_broadcast

int pthread_cond_broadcast(pthread_cond_t *cond);

功能:唤醒所有休眠队列的线程

参数: pthread_cond_t *cond:该指针指向的内存中存储条件变量

返回值:成功返回0,失败返回非0

pthread_cond_destroy

int pthread_cond_destroy(pthread_cond_t *cond);

功能:销毁条件变量

参数: pthread_cond_t *cond:该指针指向的内存中存储条件变量

返回值:成功返回0,失败返回非0