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;
}

相关推荐

  1. nng协议分析之互斥pthread_mutexattr_settype函数

    2024-03-13 11:44:04       30 阅读
  2. Go 语言互斥 Mutex

    2024-03-13 11:44:04       32 阅读
  3. 互斥、信号量、条件变量实现线程同步

    2024-03-13 11:44:04       52 阅读
  4. C语言连接数据库简单示例

    2024-03-13 11:44:04       57 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-13 11:44:04       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-13 11:44:04       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-13 11:44:04       87 阅读
  4. Python语言-面向对象

    2024-03-13 11:44:04       96 阅读

热门阅读

  1. 【C++】内存泄漏

    2024-03-13 11:44:04       37 阅读
  2. 阿里云数据盘挂载目录

    2024-03-13 11:44:04       45 阅读
  3. C++内存对齐知识点总结

    2024-03-13 11:44:04       39 阅读
  4. 运维工程师面试题

    2024-03-13 11:44:04       33 阅读
  5. 在vue中什么是虚拟DOM?

    2024-03-13 11:44:04       43 阅读
  6. 计算机网络面经八股-HTTP1.0和HTTP1.1的区别?

    2024-03-13 11:44:04       39 阅读
  7. CSS进阶空间转换和 less

    2024-03-13 11:44:04       29 阅读
  8. php7.3.4连接sqlserver(linux平台)

    2024-03-13 11:44:04       40 阅读
  9. 【Docker】APISIX Dashboard 容器化部署

    2024-03-13 11:44:04       44 阅读