Linux线程安全(二)条件变量实现线程同步

目录

条件变量

条件变量初始化和唤醒

键盘触发条件变量唤醒线程demo

条件变量的等待

条件变量定时等待demo

条线变量实现多线程间的同步


条件变量

条件变量是为了控制多个线程的同步工作而设计的

比如说一个系统中有多个线程的存在但有且仅有一个线程在工作,我们需要等待这个线程执行完任务之后然后唤醒另一个线程执行另外一个任务,

那这个时候"正在工作的这个线程执行完任务"就是一个条件变量,等这个条件变量触发之后正在工作的线程就会休眠,然后新的线程会启动。

条件变量初始化和唤醒

#include <pthread.h>

//销毁条件变量 int pthread_cond_destroy(pthread_cond_t *cond);

//初始化条件变量
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);

cond:条件变量

attr:属性默认为 NULL

返回值: 成功 0 失败 -1

#include <pthread.h>

//随机唤醒一个等待的线程 int pthread_cond_signal(pthread_cond_t *cond);

//唤醒所有正在等待的线程 int pthread_cond_broadcast(pthread_cond_t *cond);

键盘触发条件变量唤醒线程demo
cpp 复制代码
#include <stdio.h>
#include <pthread.h>

pthread_cond_t cond;
pthread_mutex_t mutex;

int n = 0;

void *task(void *arg)
{
    while (1)
    {
        printf("%ld 线程等待条件\n", pthread_self());
        pthread_cond_wait(&cond, &mutex);
        if (n == 1)
        {
            n = 0;
            printf("%ld 线程被唤醒,执行任务\n", pthread_self());
        }
    }
}

int main()
{
    // 初始化锁与条件变量
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);

    // 创建一个线程
    pthread_t tid;
    pthread_create(&tid, NULL, task, NULL);
    pthread_create(&tid, NULL, task, NULL);
    pthread_create(&tid, NULL, task, NULL);
    pthread_create(&tid, NULL, task, NULL);

    while (1)
    {
        printf("1.唤醒随机一个线程  2.唤醒所有线程\n");
        int n = 0;
        scanf("%d", &n);

        if (n == 1)
        {
            pthread_cond_signal(&cond); // 唤醒随机一个
        }
        else if (n == 2)
        {
            pthread_cond_broadcast(&cond); // 唤醒所有
        }
    }
}
条件变量的等待

#include <pthread.h>

//定时等待
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);

//一直等待
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);

cond:条件变量

mutex:互斥锁

abstime:定时器

返回值:

条件变量定时等待demo
cpp 复制代码
#include <stdio.h>
#include <pthread.h>
#include <time.h>

pthread_cond_t cond;

void *task(void *arg)
{
    while (1)
    {
        printf("输入任意键唤醒线程\n");
        getchar();
        pthread_cond_signal(&cond);
    }
}

int main()
{
    // 0.初始化互斥锁
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);

    // 1.初始化条件变量
    int ret = pthread_cond_init(&cond, NULL);
    if (ret < 0)
    {
        perror("初始化条件变量失败\n");
    }

    // 创建一个线程
    pthread_t tid;
    pthread_create(&tid, NULL, task, NULL);

    // 2.开启定时等待
    while (1)
    {
        // 设置时间
        struct timespec ts;

        //clock_gettime()获取时间函数
        //CLOCK_REALTIME:系统实时时间,可以从网络同步,也可以用户自行更改
        clock_gettime(CLOCK_REALTIME, &ts); 

#if 0  //timespec结构体,tv_sec为秒
struct timespec
{
  __time_t tv_sec;    /* Seconds.  秒*/
  __syscall_slong_t tv_nsec;  /* Nanoseconds.纳秒*/      
}           
#endif

        ts.tv_sec += 5;                     // 时间增加 5 秒
        printf("开启定时等待5秒\n");
        //pthread cond wait函数的返回值为0,代表成功等待条件变量并且收到了通知。
        //如果返回值是一个非零值,则表示函数运行出现了错误
        //需要根据错误码进行处理。
        int ret = pthread_cond_timedwait(&cond, &mutex, &ts);
        printf("等待结束 %d\n", ret);  //超时返回值110
    }
}

条线变量实现多线程间的同步

利用条件变量使三个线程轮流运作,线程1执行完之后执行线程2,线程2执行完之后执行线程3,线程3执行完之后重新执行线程1.

cpp 复制代码
#include <stdio.h>
#include <pthread.h>

// 定义三个条件
pthread_cond_t first;  // 条件1
pthread_cond_t second; // 条件2
pthread_cond_t third; // 条件3

pthread_mutex_t mutex;

void *task(void *arg)
{
    while (1)
    {
        pthread_cond_wait(&third, &mutex);
        printf("线程1运行\n");
        pthread_cond_signal(&first);
    }
}

void *task1(void *arg)
{
    while (1)
    {
        pthread_cond_wait(&first, &mutex);
        printf("线程2运行\n");
        pthread_cond_signal(&second);
    }
}

void *task2(void *arg)
{
    while (1)
    {
        pthread_cond_wait(&second, &mutex);
        printf("线程3运行\n");
        pthread_cond_signal(&third);
    }
}

int main()
{
    // 初始化条件变量与线程锁
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&first, NULL);
    pthread_cond_init(&second, NULL);
    pthread_cond_init(&third, NULL);

    // 创建三个任务线程
    pthread_t tid;
    pthread_create(&tid, NULL, task, NULL);
    pthread_t tid1;
    pthread_create(&tid1, NULL, task1, NULL);
    pthread_t tid2;
    pthread_create(&tid2, NULL, task2, NULL);

    while (1)
    {
        printf("输入任意键线程开始工作\n");
        getchar();
        pthread_cond_signal(&third);
    }
}
相关推荐
IronmanJay1 小时前
【LeetCode每日一题】——862.和至少为 K 的最短子数组
数据结构·算法·leetcode·前缀和·双端队列·1024程序员节·和至少为 k 的最短子数组
TensorFlowGAN1 小时前
rhcsa、ce复习(每日编辑,复习完为止)
linux·es
Drscq2 小时前
How to migrate a CentOS 8 to Rocky Linux 8.10
linux·运维·centos
修心光2 小时前
CentOS配置iptables规则并使其永久生效
linux·运维·centos
安科瑞刘鸿鹏2 小时前
校园建筑用电安全监测装置 电气火灾监测预防设备功能介绍
运维·服务器·网络·嵌入式硬件·安全·能源
Wx120不知道取啥名2 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
课堂随想2 小时前
【libGL error】Autodl云服务器配置ACT的conda虚拟环境生成训练数据时,遇到了libGL相关错误,涉及swrast_dri.so
运维·服务器·conda
biomooc3 小时前
R语言 | paletteer包:拥有2100多个调色板!
r语言·数据可视化·1024程序员节
Hello.Reader3 小时前
FFmpeg 深度教程音视频处理的终极工具
ffmpeg·1024程序员节