线程(三):线程通信:同步(条件变量、无名信号量)+互斥(互斥锁)

一、线程通信:互斥—>互斥锁

头文件:
#include <pthread.h>

1、定义线程互斥锁变量

pthreda_mutex_t mutex;

2、初始化互斥锁变量

2.1、静态初始化(默认模式)== 动态初始化时参数填 NULL

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

2.2、动态初始化

函数原型:
   int pthread_mutex_init(pthread_mutex_t *restrict mutex,
                const pthread_mutexattr_t *restrict attr);
参数:
    @mutex: 进行初始化的锁
    @attr : 线程属性,一般写为NULL
返回值:成功返回0   失败返回错误码

3. 上锁

函数原型:
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:上锁(尝试上锁)(如果之前锁没有被使用过,直接获取锁成功)                            
参数:    
    @mutex: 互斥锁的变量地址
返回值:成功返回0 失败错误码

4. 解锁-----不管是上锁还是尝试上锁,都用该函数解锁

函数原型:
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
参数:    
    @mutex: 互斥锁变量的首地址
返回值:成功0  失败错误码

5. 销毁锁

函数原型:
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁锁
参数:    
    @mutex: 互斥锁变量的首地址
返回值:成功0  失败错误码

二、线程通信:同步—>无名信号量

头文件

#include <semaphore.h>

1、定义无名信号量

sem_t sem;

2、初始化无名信号量

函数原型:
    int sem_init(sem_t *sem, int pshared, unsigned int value);   
参数:
    @sem: 无名信号量变量的首地址
    @pshared: 是在线程还是进程间使用
        0: 两个线程的同步 (一般01: (非0)两个进程的同步(前提,两个进程是亲缘进程)  
    @value: 无名信号量的初始值
        如果value为0:表示线程获取不到信号量,将阻塞
                     (为0 就是阻塞等,什么时候数值+1, 什么时候可以申请信号量)
        如果value非0: 表示线程可以获取无名信号量
                      (一般为1 如果填1表示一个线程可以获取资源)
返回值:成功返回0  失败-1

3、获取信号量

     int sem_wait(sem_t *sem);
功能:相当于P操作,获取信号量(如果获取不到就阻塞)
参数:
    @sem : 无名信号量的首地址
返回值:成功返回0  失败-1

4、释放信号量

    int sem_post(sem_t *sem);
功能:相当于v操作+1,释放信号量
参数:
    @sem : 无名信号量的首地址
返回值:成功返回0  失败-1

5、销毁信号量

    int sem_destroy(sem_t *sem);
功能:销毁无名信号量
参数:
    @sem : 无名信号量的首地址
返回值:成功返回0  失败-1
只有已经被 sem_init 初始化的信号量才应该使用sem_destroy()销毁。
销毁当前被其他进程或线程阻塞的信号量(未释放的信号量)会产生未定义的行为。
使用已被销毁的信号量会产生未定义的结果,直到使用 sem_init 重新初始化该信号量。 

示例:无名信号量的使用(重在理解,与参考)

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <semaphore.h>

//2. 定义无名信号量
sem_t sem1;
sem_t sem2;

//生产者线程
void *thread_handle1(void * arg){
    while(1){
        //获取无名信号量
        sem_wait(&sem1);            //sem1初始值为1,可以获取
        printf("生产一个面包\n");
        //4. 释放无名信号量
        sem_post(&sem2);
    }
}
//消费者线程
void *thread_handle2(void * arg){
    while(1){
        //获取无名信号量
        sem_wait(&sem2);            //sem2初始值为0,获取不到,阻塞
        printf("购买一个面包\n");

        
        //4. 释放无名信号量
        sem_post(&sem1);
    }
}
int main(){
    //1. 创建线程
    pthread_t tid1, tid2;
    
    if((errno = pthread_create(&tid1, NULL, thread_handle1, NULL)) != 0){
        perror("create tid1 :");return -1;
    }
    if((errno = pthread_create(&tid2, NULL, thread_handle2, NULL)) != 0){
        perror("create tid2 :");return -1;
    }
    //3. 初始化无名信号量
    sem_init(&sem1, 0, 1);
    sem_init(&sem2, 0, 0);
    
    //阻塞等待子线程结束为其回收资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    
    //5. 销毁无名信号量
    sem_destroy(&sem1);
    sem_destroy(&sem2);
    return 0;    
}

三、线程通信:同步—>条件变量

1、定义一个条件变量

pthread_cond_t cond;

2、初始化条件变量

2.1、静态初始化

 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2.2、动态初始化

   int pthread_cond_init(pthread_cond_t *restrict cond,
           const pthread_condattr_t *restrict attr);
    功能:初始化条件变量
    参数:
        @cond:条件变量首地址
        @attr:属性, NULL
    返回值:成功返回0   失败错误码

3、释放条件变量(由一个线程创造释放一个或多个条件变量)(先释放再获取)

 int pthread_cond_broadcast(pthread_cond_t *cond);
    功能:释放多个资源(释放所有资源)
    	(释放后,等待队列所有线程全部进行获取,形成队内无序,队间有序)
    参数:
         @cond: 条件变量的首地址
    返回值:成功返回0   失败错误码     
-----------------------------------------------------------------------------------------------------------------
    int pthread_cond_signal(pthread_cond_t *cond);
    功能:释放一个资源
    参数:
         @cond: 条件变量的首地址
    返回值:成功返回0 失败错误码 

4、获取条件变量(可多个线程获取)(使用前定义并初始化一个互斥锁)

   int pthread_cond_wait(pthread_cond_t *restrict cond,
       pthread_mutex_t *restrict mutex);
 参数:
     @cond: 条件变量的首地址
     @mutex: 互斥锁 
     		(在调用pthread_cond_wait函数之前要定义并初始化一个互斥锁) 
         //1. 获取互斥锁
         //2. 调用pthread_cond_wait   
             //2.1 将当前的线程放入队列里
             //2.2 解锁
             //2.3 在队列里休眠
             //2.4 重新获取锁
             //从队列删除  
         //3. 执行代码   
         //4. 解锁
返回值:成功返回0   失败错误码

5、销毁条件变量

int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁条件变量
参数:
     @cond: 条件变量的首地址
返回值:成功返回0   失败错误码 

示例:条件变量使用(一个消费者线程)(重在理解,与参考)

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <semaphore.h>

//定义条件变量
pthread_cond_t cond;
pthread_mutex_t mutex;


//生产者线程
void *thread_handle1(void * arg){
    //设为分离态
    //pthread_detach(pthread_self());
    while(1){
        sleep(1);
        printf("生产一个面包\n");
        pthread_cond_signal(&cond);    
    }
}

//消费者线程
void *thread_handle2(void * arg){
    while(1){
    pthread_cond_wait(&cond, &mutex);
        printf("购买一个面包\n");        
    }
}

int main(){
    //创建线程
    pthread_t tid1, tid2;    
    if((errno = pthread_create(&tid1, NULL, thread_handle1, NULL)) != 0){
        perror("create tid1 ");return -1;
    }
    if((errno = pthread_create(&tid2, NULL, thread_handle2, NULL)) != 0){
        perror("create tid2 ");return -1;
    }
    //初始化条件变量
    pthread_cond_init(&cond, NULL);
    
    //阻塞等待回收子线程资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    
    //销毁条件变量
    pthread_cond_destroy(&cond);
    
    return 0;
}

示例二: 条件变量使用(多个消费者线程)

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <semaphore.h>

//定义条件变量
pthread_cond_t cond;
pthread_mutex_t mutex;

//生产者线程
void *thread_handle(void * arg){
    //设为分离态
    //pthread_detach(pthread_self());
    while(1){
        sleep(1);
        //每次生产一个面包,释放一个资源
        //printf("生产一个面包\n");
        //pthread_cond_signal(&cond);    
        
        //每次生产多个,同时释放多个资源
        printf("生产5个面包\n");
        pthread_cond_broadcast(&cond);
    }
}

//消费者线程
void *thread_handle1(void * arg){
    //循环操作
    while(1){
        //1. 上锁(获取互斥锁)
        pthread_mutex_lock(&mutex);
        
        //2. 获取条件变量
        pthread_cond_wait(&cond, &mutex);
        
        //3. 执行代码
        printf("%ld 购买一个面包\n", pthread_self());        
        
        //4. 解锁
        pthread_mutex_unlock(&mutex);
    }
}

int main(){
    //创建线程
    pthread_t tid, tid1, tid2, tid3, tid4;
    
    if((errno = pthread_create(&tid, NULL,  thread_handle, NULL)) != 0){
        perror("create tid1 ");return -1;
    }
    if((errno = pthread_create(&tid1, NULL, thread_handle1, NULL)) != 0){
        perror("create tid2 ");return -1;
    }
    if((errno = pthread_create(&tid2, NULL, thread_handle1, NULL)) != 0){
        perror("create tid2 ");return -1;
    }
    if((errno = pthread_create(&tid3, NULL, thread_handle1, NULL)) != 0){
        perror("create tid2 ");return -1;
    }
    if((errno = pthread_create(&tid4, NULL, thread_handle1, NULL)) != 0){
        perror("create tid2 ");return -1;
    }

    //初始化条件变量和互斥锁变量
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    
    //打印消费者线程号
    printf("tid1 = %ld\n", tid1);
    printf("tid2 = %ld\n", tid2);
    printf("tid3 = %ld\n", tid3);
    printf("tid4 = %ld\n", tid4);
    
    //阻塞等待回收子线程资源
    pthread_join(tid, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);
    pthread_join(tid4, NULL);
    
    //销毁条件变量
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好好睡觉好好吃饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值