C语言pthread互斥锁与条件变量应用逻辑的简单示例

实验结论:

1 同一时间,只有1个线程可以获得互斥锁

2 使用默认互斥锁属性 互斥锁不可重入

3 初始化条件变量后 调用pthread_cond_wait 线程状态为S 睡眠,且释放了互斥锁

4 当线程队列中只有1条处于wait状态的线程,调用pthread_cond_signal,可以将其唤醒

5 唤醒后pthread_cond_wait不是立即返回,而是获得互斥锁后才返回

6 同理循环使用pthread_cond_signal可以随机唤醒多条等待线程

7 使用pthread_cond_broadcast可以唤醒全部等待线程

8 使用条件变量必须使用互斥锁

int pthread_cond_wait (pthread_cond_t *__restrict __cond,pthread_mutex_t *__restrict __mutex)

__nonnull ((1, 2));//表示参数1,2不可以为null

9 必须使用互斥锁保护条件变量,以下是一个未保护的情形:

   消费者消费后发现仓库为空,将要调用pthread_cond_wait之际,系统调度到生产者线程

   生产满了之后,pthread_cond_signal 消费者 因为条件变量没有受到同步保护所以先收到了signal

   后调用了 wait 导致无限期休眠

实验描述:

创建两个线程 一个发送signal 一个wait

wait先走,来到等待点,睡眠

三秒后发送条件变量信号,发现wait并没有返回,因为signal还没有释放锁

三秒后,signal释放锁,wait返回成功,全剧终

全程使用互斥锁保护条件变量

实验环境:

unix-like系统 gnu_c 或其他支持posix的系统,可在IDE下运行,也可单独编译运行

#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <pthread.h>

pthread_cond_t cond;
pthread_mutex_t mutexlock;
void *cv_wait(void *p)
{
    // 因为cv_signal上来就睡,所以cv_wait先锁
    pthread_mutex_lock(&mutexlock);
    printf("%lu pthread_cond_wait\n", pthread_self());
    // 等待并释放锁
    if (pthread_cond_wait(&cond, &mutexlock) == 0)
    {
        printf("%lu pthread_cond_wait 返回成功\n", pthread_self());
    }
    printf("pthread_cond_wait 获得互斥锁后才能返回 不是收到信号立即返回\n");
    // 解锁
    pthread_mutex_unlock(&mutexlock);
    pthread_exit(NULL);
}
void *cv_signal(void *p)
{
    pthread_t tid = *((pthread_t *)p);
    for (size_t i = 3; i > 0; i--)
    {
        sleep(1);
        printf("About to wake up %lu , %zu\n", tid, i);
    }
    sleep(1);
    // cv_wait线程先拿到锁,cond_wait函数阻塞,并没有走到mutex_unlock函数
    // 而后cv_signal 拿到了锁 说明pthread_cond_wait释放了锁
    pthread_mutex_lock(&mutexlock);
    printf("%lu pthread_cond_signal\n", pthread_self());
    // 尝试唤醒 wait状态的cv_wait线程
    pthread_cond_signal(&cond);
    // pthread_cond_signal(&cond);
    // 可以增加线程使用broadcast观察效果
    // pthread_cond_broadcast(&cond);
    // 如果此处有耗时逻辑 则需要等释放锁后 pthread_cond_wait 才能返回
    for (size_t i = 3; i > 0; i--)
    {
        printf("等%zu秒释放锁\n", i);
        sleep(1);
    }
    // 释放锁后pthread_cond_wait 才能返回
    pthread_mutex_unlock(&mutexlock);

    pthread_exit(NULL);
}
int main()
{
    pthread_mutex_init(&mutexlock, NULL);
    if (pthread_cond_init(&cond, NULL))
    {
        perror("pthread_cond_init");
    }
    pthread_t tids[3] = {0};
    pthread_create(&tids[0], NULL, cv_wait, NULL);
    // pthread_create(&tids[2], NULL, cv_wait, NULL);
    pthread_create(&tids[1], NULL, cv_signal, (void *)&tids[0]);
    pthread_join(tids[0], NULL);
    pthread_join(tids[1], NULL);
    // pthread_join(tids[2], NULL);
    pthread_mutex_destroy(&mutexlock);
    pthread_cond_destroy(&cond);
    // 进程结束
    printf("%lu all done\n", pthread_self());

    return 0;
}

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值