基于条件变量的消息队列 说明介绍

基于条件变量的消息队列是一种进程间通信机制,适用于多线程环境。在使用过程中,需要注意线程同步和互斥的问题。

什么是条件变量

条件变量是线程间同步的一种方式,线程可以调用它的wait()方法将自己阻塞,直到其他线程调用signal()方法才能重新运行。条件变量常和互斥锁配合使用,锁用来保护数据,条件变量用来等待特定条件的发生。

消息队列

消息队列是一种消息传递机制,用来在进程间或线程间传递数据。

条件变量实现消息队列

基于条件变量的消息队列可以用下面的数据结构表示:

#define QUEUE_SIZE 10
struct Queue {
    int buffer[QUEUE_SIZE];
    int head;
    int tail;
    int size;
    pthread_mutex_t mutex;
    pthread_cond_t cond_full;
    pthread_cond_t cond_empty;
};

这里的Queue是一个循环队列,buffer数组用来存储数据,head和tail记录队首和队尾的位置,size记录队列中现有元素的个数。mutex是互斥锁,用来保护队列的操作;cond_full和cond_empty是条件变量,用来提示队列是否满或空以及通知变化。

消息队列示例

接下来,我们通过两个示例来展示基于条件变量的消息队列的实现。

示例1:生产者-消费者

下面是一个简单的生产者-消费者程序:

void *producer(void *arg){
    struct Queue *queue = (struct Queue *) arg;
    while(1) {
        pthread_mutex_lock(&queue->mutex);
        while(queue->size == QUEUE_SIZE) {
            pthread_cond_wait(&queue->cond_full, &queue->mutex);
        }
        int item = rand() % 1000;
        printf("producer produced %d\n", item);
        queue->buffer[queue->tail] = item;
        queue->tail = (queue->tail + 1) % QUEUE_SIZE;
        queue->size++;
        pthread_cond_signal(&queue->cond_empty);
        pthread_mutex_unlock(&queue->mutex);
        usleep(rand() % 1000000);
    }
    return NULL;
}

void *consumer(void *arg){
    struct Queue *queue = (struct Queue *) arg;
    while(1) {
        pthread_mutex_lock(&queue->mutex);
        while(queue->size == 0) {
            pthread_cond_wait(&queue->cond_empty, &queue->mutex);
        }
        int item = queue->buffer[queue->head];
        queue->head = (queue->head + 1) % QUEUE_SIZE;
        queue->size--;
        printf("consumer consumed %d\n", item);
        pthread_cond_signal(&queue->cond_full);
        pthread_mutex_unlock(&queue->mutex);
        usleep(rand() % 1000000);
    }
    return NULL;
}

int main(){
    struct Queue q;
    q.head = 0;
    q.tail = 0;
    q.size = 0;
    pthread_mutex_init(&q.mutex, NULL);
    pthread_cond_init(&q.cond_full, NULL);
    pthread_cond_init(&q.cond_empty, NULL);
    pthread_t t1, t2;
    pthread_create(&t1, NULL, producer, &q);
    pthread_create(&t2, NULL, consumer, &q);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    return 0;
}

在这个程序中,生产者和消费者各自运行在一个线程里,它们通过向消息队列中加入或删除数据来完成通信。线程之间通过条件变量和互斥锁来同步,确保生产者只在队列不满的时候把数据添加到队尾,消费者只在队列不空的时候从队头取出数据。

示例2:线程池

下面是一个简单的线程池程序:

void *threadpool_function(void *arg){
    struct Queue *queue = (struct Queue *) arg;
    while(1) {
        pthread_mutex_lock(&queue->mutex);
        while(queue->size == 0) {
            pthread_cond_wait(&queue->cond_empty, &queue->mutex);
        }
        int fd = queue->buffer[queue->head];
        queue->head = (queue->head + 1) % QUEUE_SIZE;
        queue->size--;
        printf("thread %d processing %d\n", pthread_self(), fd);
        pthread_cond_signal(&queue->cond_full);
        pthread_mutex_unlock(&queue->mutex);
        handle_connection(fd); // 处理连接
    }
    return NULL;
}

int main(){
    struct Queue q;
    q.head = 0;
    q.tail = 0;
    q.size = 0;
    pthread_mutex_init(&q.mutex, NULL);
    pthread_cond_init(&q.cond_full, NULL);
    pthread_cond_init(&q.cond_empty, NULL);
    pthread_t t1, t2, t3;
    pthread_create(&t1, NULL, threadpool_function, &q);
    pthread_create(&t2, NULL, threadpool_function, &q);
    pthread_create(&t3, NULL, threadpool_function, &q);
    int listenfd = open_listenfd(8080);
    while(1) {
        int connfd = accept(listenfd, NULL, NULL);
        pthread_mutex_lock(&q.mutex);
        while(queue->size == QUEUE_SIZE) {
            pthread_cond_wait(&queue->cond_full, &queue->mutex);
        }
        queue->buffer[queue->tail] = connfd;
        queue->tail = (queue->tail + 1) % QUEUE_SIZE;
        queue->size++;
        pthread_cond_signal(&queue->cond_empty);
        pthread_mutex_unlock(&queue->mutex);
    }
    return 0;
}

在这个程序中,线程池由三个线程组成,它们共享一个队列。main线程不断接收客户端请求,并把套接字描述符放到队列中,工作线程从队列中取出任务,并处理连接请求。线程之间通过条件变量和互斥锁来同步,确保队列不满不空。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于条件变量的消息队列 说明介绍 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C语言实现最小生成树构造算法

    C语言实现最小生成树构造算法攻略 最小生成树(Minimum Spanning Tree,MST)是一种求加权无向连通图的生成树的算法,其可以将连通图的n个顶点连接起来,形成一个权值最小的树。本文将介绍使用C语言实现最小生成树构造算法的攻略。 算法简介 其中,Kruskal算法和Prim算法是最常用的两个求解最小生成树的算法。 Kruskal算法 Krusk…

    C 2023年5月22日
    00
  • 在Linux系统上进行openmp多线程编程的方法

    在Linux系统上进行OpenMP多线程编程的方法如下: 1. 安装OpenMP库和编译器 在Linux系统中使用OpenMP多线程编程需要安装OpenMP库和编译器。在大多数Linux系统上,OpenMP库和编译器可以通过包管理工具安装。例如,在Ubuntu系统中,可以通过以下命令安装: sudo apt-get install libomp-dev g+…

    C 2023年5月22日
    00
  • C/C++ INI文件操作实现代码

    关于C++ INI文件操作实现代码的攻略,我提供以下完整步骤: 1. 什么是INI文件 INI文件是一种配置文件,通常用于应用程序的配置、选项和设置。INI文件通常是一个文本文件,包含了特定格式的键值对。INI文件的键值对格式如下: [section] key=value 其中,[]括起来的是一个section,下面的key=value就是在这个sectio…

    C 2023年5月24日
    00
  • C++设计一个简单内存池的全过程

    下面我将详细讲解C++设计一个简单内存池的全过程。 概述 内存池是为了提高内存分配与释放效率而提出的一种技术。一般情况下,内存池会提前分配一定的内存,并将分配出的内存按照一定的规则进行管理。当需要内存时,内存池会从已经预分配的内存中寻找可以使用的内存块。当不需要使用某个内存块时,该内存块会被归还给内存池进行管理。 下面我们将按照以下步骤设计简单的内存池。 步…

    C 2023年5月23日
    00
  • Shell在日常工作中的应用实践

    作者:京东物流 李光新 1 Shell可以帮我们做什么 作为一名测试开发工程师,在与linux服务器交互过程中,大都遇到过以下这些问题: •一次申请多台服务器,多台服务器需要安装相同软件,配置相同的环境,同样的操作需要重复多次; •工作中经常会使用命令行命令来完成我们的一些操作,但是有些命令使用率很高,而且很长,每次都全部敲进去势必会浪费很多时间(比如查日志…

    C语言 2023年4月22日
    00
  • VC程序在Win32环境下动态链接库(DLL)编程原理

    VC程序在Win32环境下动态链接库(DLL)编程,主要原理是将一些可重复利用的函数和资源封装进动态链接库文件中,再由其他程序在需要时进行调用,从而提高代码重用性和程序的简洁性。以下是详细的攻略: 1. 创建DLL工程 首先,在VC中新建Win32 DLL工程,在“Win32 Application Wizard”对话框中选择“DLL”类型,之后通过向导一步…

    C 2023年5月23日
    00
  • PHP如何抛出异常处理错误

    异常处理是在程序运行时检测到错误时的一种标准处理方式。PHP 使用 try/catch 语句块来实现异常处理。 1. 抛出异常 PHP 中可以使用 throw 关键字抛出一个异常。 throw new Exception(‘这是一个异常信息’); 以上代码会抛出一个 Exception 类型的异常,并且在异常对象中保存了一个字符串“这是一个异常信息”。 2.…

    C 2023年5月23日
    00
  • C++之类和对象课后习题简单实例

    针对“C++之类和对象课后习题简单实例”的完整攻略,可以从以下几个方面进行讲解: 一、题目理解 在做习题前,首先需要充分理解题意,这里应该明确以下几个点: 题目要求实现的是什么功能?如何输入数据,如何输出结果? 题目给出的限制条件是什么?需要注意哪些细节问题? 题目解答需要用到哪些知识点和技巧? 比如有如下一道题目: 假设有一个 Point 类,表示平面上的…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部