线程的同步与互斥

目录

一、相关概念

1.互斥的定义

2.同步的定义

二、互斥问题及解决方案

1.互斥锁(mutex)(独占锁)

(1)互斥锁机制

(2)互斥锁的操作

a.申请互斥锁---->

b.上锁---->pthread_mutex_lock

c.解锁---->pthread_mutex_unlock

d.回收互斥锁---->pthread_mutex_destroy

(3)互斥锁具体使用

2.读写锁(rwlock)

(1)读写锁机制

(2)读写锁的操作

a.申请初始化读写锁---->

b.读上锁---->pthread_rwlock_rdlock

c.写上锁---->pthread_rwlock_wrlock

d.解锁---->pthread_rwlock_unlock

e.回收互斥锁---->pthread_rwlock_destroy

(3)读写锁具体使用

3.信号量(semaphore)

(1)信号量机制

(2)信号量应用场景

(3)信号量典型应用

三、同步问题及解决方案

1.条件变量

(1)条件变量机制

(2)条件变量的操作

a.申请初始化条件变量---->

b.条件变量阻塞---->pthread_cond_wait

c.条件变量通知---->pthread_cond_signal

                         ---->pthread_cond_broadcast

d.回收条件变量---->pthread_cond_destroy()

(3)条件变量的应用场景

2.信号量(semphore)(POSIX标准)

(1)POSIX有名信号量:(用于进程间同步互斥)

a.创建---->sem_open

(2)POSIX无名信号量:(用于线程间同步互斥)

a.创建---->sem_init

b.P操作---->sem_wait

c.V操作---->sem_post

d.回收---->sem_destroy

(3)信号量用于同步问题解决

(4)信号量用于同步问题的典型应用


一、相关概念

1.互斥的定义

        对同一资源的访问同时仅允许一个访问者,互斥具有唯一性与排他性,互斥无法保证访问者的访问顺序

2.同步的定义

        在互斥的基础上,实现对同一资源的有序访问

二、互斥问题及解决方案

1.互斥锁(mutex)(独占锁)

(1)互斥锁机制

a.互斥锁是内核提供的一个用于共享资源互斥访问的内核资源。

b.互斥锁有两种状态:上锁、解锁

c.如果一个线程希望上锁一个已经被上锁的互斥锁,则线程阻塞,直到互斥锁处于解锁状态。

d.如果每个线程在共享资源访问前都对互斥锁进行上锁操作,那么系统只能满足一个线程的上锁操作请求,其他线程将被阻塞,这样就可以保证共享资源在同一时刻仅有一个访问者进行访问。

(2)互斥锁的操作

a.申请互斥锁---->

                     ---->静态初始化pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

                     ---->动态初始化pthread_mutex_init

//头文件
#include 

//函数原型
int pthread_mutex_init(pthread_mutex_t mutex,pthread_mutexattr_t attr);

①函数功能: 初始化互斥锁

②函数参数: mutex:待初始化的互斥锁

                           attr:锁属性,NULL代表快速互斥锁,attr 取值可以为以下3种:

                                        PTHREAD_MUTEX_INITIALIZER: 快速互斥锁

                                        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_UP: 递归互斥锁

                                        PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_UP: 检错互斥锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码

b.上锁---->pthread_mutex_lock
//头文件
#include 

//函数原型
int pthread_mutex_lock(pthread_mutex_t *mutex);

①函数功能: 上锁互斥锁

②函数参数: mutex: 待操作的互斥锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码

c.解锁---->pthread_mutex_unlock
//头文件
#include 

//函数原型
int pthread_mutex_unlock(pthread_mutex_t *mutex);

①函数功能: 解锁互斥锁

②函数参数: mutex: 待操作的互斥锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

d.回收互斥锁---->pthread_mutex_destroy
//头文件
#include 

//函数原型
int pthread_mutex_destroy(pthread_mutex_t *mutex);

①函数功能: 回收互斥锁

②函数参数: mutex: 待操作的互斥锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

(3)互斥锁具体使用

        a.共享资源访问前上锁;

        b.共享资源访问结束后解锁;

2.读写锁(rwlock)

(1)读写锁机制

a.与互斥锁类似,只是读写锁在上锁操作时,细化为读上锁和写上锁两种操作。

b.读上锁可以让线程共享访问同一资源,写上锁只能独占访问资源。

c.如果针对读访问与写访问的场合,读访问者在同一资源访问前读上锁,不阻塞可以共享访问,无疑会提高资源的访问效率

d.使用场合

        读访问者数量 > 1

(2)读写锁的操作

a.申请初始化读写锁---->

                                ---->静态初始化pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

                                ---->动态初始化pthread_rwlock_init

//头文件
#include 

//函数原型
int pthread_rwlock_init(pthread_rwlock_t rwlock,pthread_rwlockattr_t attr);

①函数功能: 初始化读写锁

②函数参数: rwlock:待初始化的读写锁

                           attr: 锁属性,NULL代表快速读写锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码

b.读上锁---->pthread_rwlock_rdlock
//头文件
#include 

//函数原型
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

①函数功能: 读上锁读写锁

②函数参数: mutex: 待操作的读写锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

c.写上锁---->pthread_rwlock_wrlock
//头文件
#include 

//函数原型
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

①函数功能: 读上锁读写锁

②函数参数: mutex: 待操作的读写锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

d.解锁---->pthread_rwlock_unlock
//头文件
#include 

//函数原型
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

①函数功能: 解锁读写锁

②函数参数: mutex: 待操作的读写锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

e.回收互斥锁---->pthread_rwlock_destroy
//头文件
#include 

//函数原型
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

①函数功能: 回收读写锁

②函数参数: rwlock:待操作的读写锁

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

(3)读写锁具体使用

a.共享资源访问前,如果访问者是读访问资源,读上锁;

b.共享资源访问前,如果访问者是写访问资源,写上锁;

c.共享资源访问结束后解锁;

3.信号量(semaphore)

(1)信号量机制

信号量用于线程互斥,往往仅需要一个信号量,且将信号量的初值设为资源总数;

每个线程在访问共享资源前对该信号量做P操作,资源访问结束后,对信号量做V操作。

(2)信号量应用场景

资源总数 > 1

(3)信号量典型应用

哲学家就餐

三、同步问题及解决方案

1.条件变量

(1)条件变量机制

a.条件变量不像互斥锁那样竞争访问共享资源,条件变量是用来阻塞线程的,直到某个条件成立,条件变量要搭配互斥锁一起使用,原因是条件的判断是要在互斥锁的保护下进行的

b.也就是说,在条件判断的同时,条件是不能被其他线程修改的。

c.条件变量在阻塞第一个线程的同时,会解开用于保护条件的互斥锁。

d.更改条件的线程,可以向条件变量发送信号通知,唤醒被阻塞的线程,线程重新评估条件,再决定是否继续运行

(2)条件变量的操作

a.申请初始化条件变量---->

                  静态初始化---->pthread_cond_t cond = PTHREAD_COND_INITIALIZER

                  动态初始化---->pthread_cond_init()

//头文件
#include

//函数原型
int pthread_cond_init(pthread_cond_t* cond,pthread_condattr_t* attr);

①函数功能:初始化条件变量

②函数参数

        cond:待初始化的条件变量

           attr: 条件变量属性,NULL代表缺省属性:

③函数返回值

        成功 : 返回0

        失败 : 返回 错误码

b.条件变量阻塞---->pthread_cond_wait
//头文件
#include 

//函数原型
int pthread_cond_wait(pthread_cond_t cond,pthread_mutex_t mutex);

①函数功能: 用条件变量阻塞调用线程,同时解锁mutex

②函数参数: cond:待初始化的条件变量

                     mutex:待解锁的互斥锁:

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

c.条件变量通知---->pthread_cond_signal
                         ---->pthread_cond_broadcast
//头文件
#include 

//函数原型
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

①函数功能: 通知条件变量,唤醒被条件变量阻塞的线程

②函数参数: cond: 待初始化的条件变量

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

d.回收条件变量---->pthread_cond_destroy()
//头文件
#include 

//函数原型
int pthread_cond_destroy(pthread_cond_t *cond);

①函数功能: 回收条件变量

②函数参数: cond: 待初始化的条件变量

③函数返回值: 成功 : 返回0

                        失败 : 返回 错误码。

(3)条件变量的应用场景

        对共享资源的有条件访问

2.信号量(semphore)(POSIX标准)

(1)POSIX有名信号量:(用于进程间同步互斥)

a.创建---->sem_open
//头文件
#include 
#include 
#include 

//函数原型
sem_t* sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag,
mode_t mode, unsigned int value);

①函数功能: 创建或者打开Posix有名信号量

②函数参数: name:有名信号量名称

                        oflag:有名信号量标志:

                       mode: 若创建,mode代表新创建的信号量权限

                        value:新创建信号量的初值

③函数返回值: 成功:返回新创建信号量地址

                        失败:返回 SEM_FAILED。错误码放在errno中

(2)POSIX无名信号量:(用于线程间同步互斥)

a.创建---->sem_init
//头文件
#include 

//函数原型
int sem_init(sem_t *sem,int pshared,int value);

①函数功能: 初始化posix无名信号量

②函数参数: sem:待初始化的信号量

               psharead: 只能指定为0

                      value: 信号量的初值

③函数返回值:成功:返回0

                         失败:-1 错误码放在errno。

b.P操作---->sem_wait
//头文件
#include 
                        
//函数原型
int sem_wait(sem_t *sem,pthread_mutex_t *mutex);

①函数功能: 阻塞调用线程,并释放mutex互斥锁

②函数参数: sem:用于阻塞线程的信号量

                    mutex: 待解锁的互斥锁:

③函数返回值:成功:返回0

                         失败: -1 错误码放在errno。

c.V操作---->sem_post
//头文件
#include 

//函数原型
int sem_post(sem_t *sem);

①函数功能: 对信号量值+1

②函数参数: sem:待操作的信号量

③函数返回值: 成功:返回0

                        失败:-1 错误码放在errno。

d.回收---->sem_destroy
//头文件
#include 

//函数原型
int sem_destroy(sem_t *sem);

①函数功能: 回收信号量

②函数参数: sem:待操作的信号量

③函数返回值: 成功:返回0

                        失败 : -1 错误码放在errno。

(3)信号量用于同步问题解决

        a.信号量用于同步问题,往往需要多个信号量,让其中一个信号量的初值设为资源总数,其余都设为0;

        b.若想让某个线程先访问共享资源,在访问共享资源前让其对初值非0的信号量做P操作,其余线程在共享资源访问前对初值为0的信号量做P操作

        c.共享资源访问结束后,先访问资源的线程对初值为0的信号量做V操作,其他线程访问结束后,对初值非0的信号量做V操作。

(4)信号量用于同步问题的典型应用

        a.生产者消费者问题:也叫有限缓冲问题

        b.该问题描述了两个线程(生产者/消费者)对共享缓冲区访问,生产者向缓冲区写入数据,消费者从缓冲区读取数据

        c.该问题的关键

                ①保证生产者线程在共享缓冲区满容量时不允许访问

                ②保证消费者在共享缓冲区为空时,不能读取数据

你可能感兴趣的:(Linux,系统开发,线程同步,线程互斥,互斥锁,读写锁,信号量,条件变量,系统开发)