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);
    }
}
相关推荐
搬砖的小码农_Sky1 小时前
C语言:数组
c语言·数据结构
sinat_384241091 小时前
使用 npm 安装 Electron 作为开发依赖
服务器
朝九晚五ฺ1 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
自由的dream1 小时前
Linux的桌面
linux
xiaozhiwise2 小时前
Makefile 之 自动化变量
linux
Kkooe3 小时前
GitLab|数据迁移
运维·服务器·git
久醉不在酒3 小时前
MySQL数据库运维及集群搭建
运维·数据库·mysql
意疏4 小时前
【Linux 篇】Docker 的容器之海与镜像之岛:于 Linux 系统内探索容器化的奇妙航行
linux·docker
虚拟网络工程师4 小时前
【网络系统管理】Centos7——配置主从mariadb服务器案例(下半部分)
运维·服务器·网络·数据库·mariadb