Linux系统编程-(pthread)线程通信(条件变量)

简介: 条件变量是线程可用的一种同步机制,条件变量给多个线程提供了一个回合的场所,条件变量和互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生。条件变量本身是由互斥体保护的,线程在改变条件状态之前必须首先锁住互斥量,其他线程在获取互斥量之前就不会觉察到这种变化,因为互斥量必须锁定之后才改变条件。

1. 条件变量介绍

条件变量是线程可用的一种同步机制,条件变量给多个线程提供了一个回合的场所,条件变量和互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生。

条件变量本身是由互斥体保护的,线程在改变条件状态之前必须首先锁住互斥量,其他线程在获取互斥量之前就不会觉察到这种变化,因为互斥量必须锁定之后才改变条件。

条件变量总结:

  1. 条件变量要配合互斥锁使用。
  2. 条件变量支持单个唤醒和广播方式唤醒。

下面是视频监控的一个项目模型,摄像头的数据使用条件变量保护:

image-20211219155142591

2. 条件变量相关接口函数

2.1 条件变量初始化与销毁

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
用法示例示例:
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);

int pthread_cond_destroy(pthread_cond_t *cond);
成功返回0,否则返回错误码

pthread_cond_init 用于初始化条件变量,最后使用完毕需要调用pthread_cond_destroy销毁。

2.2 条件变量等待与唤醒

#include<pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal (pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

pthread_cond_broadcast 函数用于广播唤醒所有等待条件的休眠线程。

pthread_cond_signal函数按顺序唤醒一个休眠的线程。

pthread_cond_wait 函数阻塞方式等待条件成立。第二个参数填互斥锁指针。

总结:

pthread_cond_signal函数一次性可以唤醒阻塞队列中的一个线程,pthread_cond_broadcast函数一次性可以唤醒阻塞队列中的所有线程。

3. 案例代码: 条件变量使用案例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>

pthread_cond_t cond;
pthread_mutex_t mutex;
/*
线程工作函数--消费者
*/
void *thread_work_func(void *dev)
{
    int i=(int)dev;
    printf("第%d个线程等待运行...\n",i);

    //互斥锁上锁
    pthread_mutex_lock(&mutex);
    printf("互斥锁上锁成功.%d \n",i);
    pthread_cond_wait(&cond,&mutex); //内部先解锁再加锁
    pthread_mutex_unlock(&mutex);
    printf("第%d个线程开始运行...\n",i);
}

//信号工作函数---生产者
void signal_work_func(int sig)
{
    printf("正在唤醒休眠的线程.\n");
    pthread_mutex_lock(&mutex);
    pthread_cond_broadcast(&cond); //广播唤醒
    //pthread_cond_signal (&cond); //唤醒单个休眠的线程
    pthread_mutex_unlock(&mutex);
}

int main(int argc,char **argv)
{   
    //注册要捕获的信号
    signal(SIGINT,signal_work_func);

    //初始化条件变量
    pthread_cond_init(&cond,NULL);
    //初始化互斥锁
    pthread_mutex_init(&mutex,NULL);
    
    /*创建子线程*/
    pthread_t thread_id;
    int i;
    for(i=0;i<10;i++)
    {
        if(pthread_create(&thread_id,NULL,thread_work_func,(void*)i)!=0)
        {
            printf("子线程%d创建失败.\n",i);
            return -1;
        }
        //设置线程的分离属性
        pthread_detach(thread_id);
        sleep(1);
    }

    while(1)
    {

    }

    //销毁条件变量
    pthread_cond_destroy(&cond);
    //销毁互斥锁
    pthread_mutex_destroy(&mutex);

    return 0;
}
目录
相关文章
|
12天前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
29 1
[Java]线程生命周期与线程通信
|
9天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
13天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
12 1
|
13天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
26 1
|
13天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
21 1
|
23天前
|
监控 安全 算法
线程死循环确实是多线程编程中的一个常见问题,它可能导致应用程序性能下降,甚至使整个系统变得不稳定。
线程死循环是多线程编程中常见的问题,可能导致性能下降或系统不稳定。通过代码审查、静态分析、日志监控、设置超时、使用锁机制、测试、选择线程安全的数据结构、限制线程数、使用现代并发库及培训,可有效预防和解决死循环问题。
42 1
|
24天前
|
Java
|
27天前
|
监控 安全 算法
线程死循环是多线程编程中的常见问题,可能导致应用性能下降甚至系统不稳定。
【10月更文挑战第6天】线程死循环是多线程编程中的常见问题,可能导致应用性能下降甚至系统不稳定。为了解决这一问题,可以通过代码审查、静态分析、添加日志监控、设置超时机制、使用锁和同步机制、进行全面测试、选用线程安全的数据结构、限制线程数量、利用现代并发库,并对团队进行培训等方法来预防和减少死循环的发生。尽管如此,多线程编程的复杂性仍需要持续监控和维护以确保系统稳定。
49 3
|
29天前
|
网络协议 Linux 网络性能优化
Linux C/C++之TCP / UDP通信
这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。
35 0
Linux C/C++之TCP / UDP通信
|
24天前
多线程通信和同步的方式有哪些?
【10月更文挑战第6天】
81 0