Linux POSIX线程库中线程同步的三种常用方式

一、互斥锁(互斥)
使用步骤:
1、定义一个互斥锁变量:pthread_mutex_t mutex;
2、初始化互斥锁:预设互斥锁的初始值:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER(编译时初始化锁位解锁状态)

初始化互斥锁的函数
(a)函数原型
#include <pthread.h>

                int pthread_mutex_init(pthread_mutex_t *restrict mutex,
                                                          const pthread_mutexattr_t *restrict  attr);
                
                · 功能:初始化定义的互斥锁
                     什么是初始化,就是设置互斥锁所需要的值。
                            
                · 返回值
                     总是返回0,所以这个函数不需要进行出错处理。
                     
                     
                · 参数
                  - mutex:互斥锁,需要我们自己定义。
                     比如:pthread_mutex_t mutex;
                       
                     pthread_mutex_t是一个结构体类型,所以mutex实际上是一个结构体变量。
                     
                  - attr:互斥锁的属性
                       设置NULL表示使用默认属性,除非我们想要实现一些互斥锁的特殊功能,否则默认属
                     性就够用了。

3、加锁解锁

pthread_mutex_lock(&mutex)(阻塞加锁)访问临界区加锁操作
pthread_mutex_trylock( &mutex)(非阻塞加锁); pthread_mutex_lock() 类似,不同的是在锁已经被占据时返回 EBUSY 而不是挂起等待。
pthread_mutex_unlock(&mutex): 访问临界区解锁操
4、进程退出时销毁互斥锁

pthread_mutex_destroy
(a)函数原型
#include <pthread.h>

             int pthread_mutex_destroy(pthread_mutex_t *mutex);
           
           (b)功能:销毁互斥锁
                  所谓销毁,说白了就是删除互斥锁相关的数据,释放互斥锁数据所占用的各种内存资源。
           
           (c)返回值:成功返回0,失败返回非零错误号

二、信号量(同步)
线程信号量的使用步骤:
1、定义信号量集合

信号量集合需要我们自己定义,

                          比如:sem_t sem[3],
                          线程信号量集合其实就是一个数组,数组每个元素就是一个信号量。
                          
                          sem[0]:第一个信号量
                          sem[1]:第二个信号量
                          sem[2]:第三个信号量

2、初始化集合中的每个信号量

初始化信号量的函数
(a)函数原型
#include <semaphore.h>

                int sem_init(sem_t *sem, int pshared, unsigned int value);
           
                · 功能
                  初始化线程信号量集合中的某个信号量,给它设置一个初始值。
           
                · 返回值
                  成功返回0,失败返回-1,errno被设置。
                  注意信号量的错误号不是返回的,而是设置到errno中。
                
                · 参数
                  - sem:信号量集合中的某个信号量
                  
                          信号量集合需要我们自己定义,
                          
                          比如:sem_t sem[3],
                          线程信号量集合其实就是一个数组,数组每个元素就是一个信号量。
                          
                          sem[0]:第一个信号量
                          sem[1]:第二个信号量
                          sem[2]:第三个信号量
                          
                          sem_init(&sem[0], int pshared, unsigned int value);
                  
                       线程信号量集合其实就是自定义的一个数组,而进程信号量集合则是通过semget函数创建的。
                       
                       我们只要把数组定义为全局变量,所有的线程即可共享使用,不像进程信号量,需要semid
                     才能实现共享操作。
                     
                     
                  - pshared:
                    + 0:给线程使用
                    + !0:可以给进程使用
                        不过对于进程来说,我们更多的还是使用进程信号量,因为线程信号量用到
                      进程上时,存在一些不稳定的情况。
                
                  - value:初始化值
                   对于二值信号量来说,要么是1,要么是0。

3、p、v操作

P操作
(a)函数原型
#include <semaphore.h>

                int sem_wait(sem_t *sem);//阻塞p操作
        
                
             · 功能:阻塞p操作集合中某个信号量,值-1
                如果能够p操作成功最好,否则就阻塞直到p操作操作成功为止。
                
                
             · 返回值:成功返回0,失败返回-1,errno被设置。
             
             · 参数:p操作的某个信号量。
                比如:sem_wait(&sem[0]);
             
             · sem_wait的兄弟函数
                  
                  int sem_trywait(sem_t *sem):不阻塞
                     如果能够p操作就p操作,如果不能p操作就出错返回,不会阻塞。
                  
                  int sem_timedwait(sem_t *sem, const struct timespec  *abs_timeout);
                     可以设置阻塞时间,如果能够p操作就p操作,不能就阻塞,如果在设置的时间内好没有
                     p操作成功就是出错返回,不再阻塞。
                  
                  这两个函数了解即可,不需要掌握,如果你真的用到了,自己举一反三即可搞定。
                
                  
           (b)代码演示
                sem_wait(&sem[0]); 
                  
                  
                  
        4)v操作
           (a)函数原型
                #include <semaphore.h>

                int sem_post(sem_t *sem);
           
                · 功能:对某个信号量进行v操作,v操作不存在阻塞问题。
                     v操作成功后,信号量的值会+1
                
                · 返回值:成功返回0,失败返回-1,errno被设置。
                
           (b)代码演示
                sem_post(&sem[0]);

    在实际代码开发中,sem_wait和sem_post是成对出现的。

4、进程结束时,删除线程信号量结合

删除信号量
(a)函数原型
#include <semaphore.h>

                  int sem_destroy(sem_t *sem);
                
              · 功能:删除某个信号量,把所有信号量都删除后,信号量集合就被销毁。
              
                  这与删除进程信号量集合有所不同,对于进程信号量集合来说,只要删除一个信号量,整个集合
                即被删除,但是对于线程信号量来说,需要一个一个的删除,当所有信号量都删除完后,集合才被
                删除完毕。

三、条件变量
条件变量的使用步骤:
1、定义一个条件变量(全局变量)由于条件变量需要互斥锁的配合,所以还需要定义一个线程互斥锁pthread_cond_t
2、初始化条件变量

函数原型
#include <pthread.h>

             int pthread_cond_init(pthread_cond_t *restrict cond,const  pthread_condattr_t *restrict attr);
        
           · 功能
                初始化条件变量,与互斥锁的初始化类似。
                pthread_cond_t cond; //定义条件变量
                pthread_cond_init(&cond, NULL); //第二个参数为NULL,表示不设置条件变量的属性。
                
                也可以直接初始化:
                pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//与互斥锁的初始化的原理是一样的
             
             
           · 返回值:成功返回0,失败返回非零错误号
           · 参数
             - cond:条件变量
             - attr:用于设置条件变量的属性,设置为NULL,表示使用默认属性

3、使用条件变量

2)等待条件的函数

        (a)函数原型
             #include <pthread.h>
             
             int pthread_cond_wait(pthread_cond_t *restrict cond,  pthread_mutex_t *restrict mutex);
           
             · 功能:
                  检测条件变量cond,如果cond没有被设置,表示条件还不满足,别人还没有对cond进行设置,此时
                pthread_cond_wait会休眠(阻塞),直到别的线程设置cond表示条件准备好后,才会被唤醒。
                
             · 返回值:成功返回0,失败返回非零错误号
             
             · 参数
                - cond:条件变量
                - mutex:和条件变量配合使用的互斥锁    
             
           
        (c)pthread_cond_wait的兄弟函数
             int pthread_cond_timedwait(pthread_cond_t *restrict cond, \
                             pthread_mutex_t *restrict mutex, const struct timespec  *restrict abstime);
                
                  多了第三个参数,用于设置阻塞时间,如果条件不满足时休眠(阻塞),但是不会一直休眠,
                当时间超时后,如果cond还没有被设置,函数不再休眠。
   
                  
                  
      3)设置条件变量的函数   
      
        (a)函数原型
             #include <pthread.h>
             
             int pthread_cond_signal(pthread_cond_t *cond);
             
             
           · 功能
                当线程将某个数据准备好时,就可以调用该函数去设置cond,表示条件准备好了,
             pthread_cond_wait检测到cond被设置后就不再休眠(被唤醒),线程继续运行,使用别的线程
             准备好的数据来做事。
                
                当调用pthread_cond_wait函数等待条件满足的线程只有一个时,就是用pthread_cond_signal
             来唤醒,如果说有好多线程都调用pthread_cond_wait在等待时,使用
                int pthread_cond_broadcast(pthread_cond_t *cond);
                
                它可以将所有调用pthread_cond_wait而休眠的线程都唤醒。
      
      
        (b)代码演示
             
             调用pthread_cond_signal去设置条件变量,相当是给pthread_cond_wait发送了一个线程间专
           用的信号,通知调用pthread_cond_wait的线程,某某条件满足了,不要再睡了,赶紧做事吧。

4、删除条件变量

删除条件变量
(a)函数原型
#include <pthread.h>

             int pthread_cond_destroy(pthread_cond_t *cond);
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值