热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux平台上C语言实现异步队列的两种方法

为什么80%的码农都做不了架构师?Linux上目前有两种事件通知方式,一种是线程条件变量,一种是利用eventfd实现事件通知&#x

为什么80%的码农都做不了架构师?>>>   hot3.png

Linux上目前有两种事件通知方式,一种是线程条件变量,一种是利用eventfd实现事件通知,下面介绍一下利用这两种方法实现异步队列的方法。 ###线程条件变量 ####相关函数介绍

  • pthread_cond_init:初始化一个线程条件变量。
  • pthread_cond_wait:等待条件触发。
  • pthread_cond_signal:通知一个线程,线程条件发生。
  • pthread_cond_timedwait:等待条件触发,可以设置超时时间。
  • pthread_cond_reltimedwait_np:和pthread_cond_timedwait使用基本相同,区别是使用的是相对时间间隔而不是绝对时间间隔。
  • pthread_cond_broadcast:通知所有等待线程,线程条件发生。
  • pthread_cond_destroy:销毁条件变量。

####唤醒丢失问题 如果线程未持有与条件相关联的互斥锁,则调用 pthread_cond_signal() 或 pthread_cond_broadcast() 会产生唤醒丢失错误。满足以下所有条件时,即会出现唤醒丢失问题:

  • 一个线程调用 pthread_cond_signal() 或 pthread_cond_broadcast()
  • 另一个线程已经测试了该条件,但是尚未调用 pthread_cond_wait()
  • 没有正在等待的线程

信号不起作用,因此将会丢失,仅当修改所测试的条件但未持有与之相关联的互斥锁时,才会出现此问题。只要仅在持有关联的互斥锁同时修改所测试的条件,即可调用 pthread_cond_signal() 和 pthread_cond_broadcast(),而无论这些函数是否持有关联的互斥锁。

####线程条件变量使用方法

get_resources(int amount)
{ pthread_mutex_lock(&rsrc_lock); while (resources }add_resources(int amount)
{pthread_mutex_lock(&rsrc_lock);resources += amount;pthread_cond_broadcast(&rsrc_add);pthread_mutex_unlock(&rsrc_lock);}

###eventfd

int eventfd(unsigned int initval, int flags);

eventfd是Linux提供内核态的事件等待/通知机制,内核维护了一个8字节的整型数,该整型数由initval来初始化,flags参数可以由以下值位或而来:

  • EFD_CLOEXEC:设置该描述符的O_CLOEXEC标志。
  • EFD_NONBLOCK:设置描述符为非阻塞模式。
  • EFD_SEMAPHORE:设置描述符为信号量工作模式,在此模式下,read模式会使整型数减1并返回数值1。

当内核维护的8字节整型数为0时,read操作会阻塞,如果为fd设置为非阻塞模式,则返回EAGAIN错误。

###简单的唤醒队列

下面我们实现一个简单的环形队列:

#define default_size 1024typedef struct queue
{int header;int tail;int size;int capcity;void **_buf;
} queue_t;queue_t *queue_create(int size)
{queue_t *q = malloc(sizeof (queue_t));if (q != NULL){if (size > 0){q->_buf = malloc(size);q->capcity = size;}else{q->_buf = malloc(default_size * sizeof (void *));q->capcity = default_size;}q->header = q->tail = q->size = 0;}return q;
}int queue_is_full(queue_t *q)
{return q->size == q->capcity;
}int queue_is_empty(queue_t *q)
{return q->size == 0;
}void queue_push_tail(queue_t *q, void *data)
{if (!queue_is_full(q)){q->_buf[q->tail] = data;q->tail = (q->tail + 1) % q->capcity;q->size++;}
}void *queue_pop_head(queue_t *q)
{void *data = NULL;if (!queue_is_empty(q)){data = q->_buf[(q->header)];q->header = (q->header + 1) % q->capcity;q->size--;}return data;
}int *queue_free(queue_t *q)
{free(q->_buf);free(q);
}

###线程变量实现的异步队列

typedef struct async_queue
{pthread_mutex_t mutex;pthread_cond_t cond;int waiting_threads;queue_t *_queue;
} async_queue_t;
async_queue_t *async_queue_create(int size)
{async_queue_t *q = malloc(sizeof (async_queue_t));q->_queue = queue_create(size);q->waiting_threads = 0;pthread_mutex_init(&(q->mutex), NULL);pthread_cond_init(&(q->cond), NULL);return q;
}void async_queue_push_tail(async_queue_t *q, void *data)
{if (!queue_is_full(q->_queue)){pthread_mutex_lock(&(q->mutex));queue_push_tail(q->_queue, data);if (q->waiting_threads > 0){pthread_cond_signal(&(q->cond));}pthread_mutex_unlock(&(q->mutex));}}void *async_queue_pop_head(async_queue_t *q, struct timeval *tv)
{void *retval = NULL;pthread_mutex_lock(&(q->mutex));if (queue_is_empty(q->_queue)){q->waiting_threads++;while (queue_is_empty(q->_queue)){pthread_cond_wait(&(q->cond), &(q->mutex));}q->waiting_threads--;}retval = queue_pop_head(q->_queue);pthread_mutex_unlock(&(q->mutex));return retval;
}void async_queue_free(async_queue_t *q)
{queue_free(q->_queue);pthread_cond_destroy(&(q->cond));pthread_mutex_destroy(&(q->mutex));free(q);
}

###eventfd实现的异步队列

typedef struct async_queue
{int efd; //event fdfd_set rdfds; //for selectqueue_t *_queue;
} async_queue_t;
async_queue_t *async_queue_create(int size)
{async_queue_t *q = malloc(sizeof (async_queue_t));q->efd = eventfd(0, EFD_SEMAPHORE|EFD_NONBLOCK);q->_queue = queue_create(size);FD_ZERO(&(q->rdfds));FD_SET(q->efd, &(q->rdfds));return q;
}void async_queue_push_tail(async_queue_t *q, void *data)
{unsigned long long i = 1;if (!queue_is_full(q->_queue)){queue_push_tail(q->_queue, data);write(q->efd, &i, sizeof (i));}
}void *async_queue_pop_head(async_queue_t *q, struct timeval *tv)
{unsigned long long i = 0;void *data = NULL;if (select(q->efd + 1, &(q->rdfds), NULL, NULL, tv) == 0){return data;}else{read(q->efd, &i, sizeof (i));return queue_pop_head(q->_queue);}
}void async_queue_free(async_queue_t *q)
{queue_free(q->_queue);close(q->efd);free(q);
}

###总结 两种实现方法线程条件变量比较复杂,但是性能略高,而eventfd实现简单,但是性能略低。


转:https://my.oschina.net/sundq/blog/203600



推荐阅读
  • ipsec 加密流程(二):ipsec初始化操作
    《openswan》专栏系列文章主要是记录openswan源码学习过程中的笔记。Author:叨陪鲤Email:vip_13031075266163.comDate:2020.1 ... [详细]
  • 在iOS开发中,多线程技术的应用非常广泛,能够高效地执行多个调度任务。本文将重点介绍GCD(Grand Central Dispatch)在多线程开发中的应用,包括其函数和队列的实现细节。 ... [详细]
  • 在运行于MS SQL Server 2005的.NET 2.0 Web应用中,我偶尔会遇到令人头疼的SQL死锁问题。过去,我们主要通过调整查询来解决这些问题,但这既耗时又不可靠。我希望能找到一种确定性的查询模式,确保从设计上彻底避免SQL死锁。 ... [详细]
  • 用C语言实现的科学计算器,支持2种常量,10种基本函数,Ans寄存器。相对来说拓展性应该是不错的,思路是首先化简复杂名称的函 ... [详细]
  • 在尝试将 mysqldump 文件加载到新的 MySQL 服务器时,遇到因使用保留关键字 'table' 导致的语法错误。 ... [详细]
  • WPF项目学习.一
    WPF项目搭建版权声明:本文为博主初学经验,未经博主允许不得转载。一、前言记录在学习与制作WPF过程中遇到的解决方案。使用MVVM的优点是数据和视图分离,双向绑定,低耦合,可重用行 ... [详细]
  • 自然语言处理(NLP)——LDA模型:对电商购物评论进行情感分析
    目录一、2020数学建模美赛C题简介需求评价内容提供数据二、解题思路三、LDA简介四、代码实现1.数据预处理1.1剔除无用信息1.1.1剔除掉不需要的列1.1.2找出无效评论并剔除 ... [详细]
  • 在Java开发中,保护代码安全是一个重要的课题。由于Java字节码容易被反编译,因此使用代码混淆工具如ProGuard变得尤为重要。本文将详细介绍如何使用ProGuard进行代码混淆,以及其基本原理和常见问题。 ... [详细]
  • RTThread线程间通信
    线程中通信在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取& ... [详细]
  • 尽管Medium是一个优秀的发布平台,但在其之外拥有自己的博客仍然非常重要。这不仅提供了另一个与读者互动的渠道,还能确保您的内容安全。本文将介绍如何使用Bash脚本将Medium文章迁移到个人博客。 ... [详细]
  • Spring 中策略模式的应用:Resource 接口详解
    本文探讨了在 Spring 框架中如何利用 Resource 接口实现资源访问策略。Resource 接口作为资源访问策略的抽象,通过多种实现类支持不同类型的资源访问。 ... [详细]
  • 本文将详细介绍如何在 Vue 项目中使用 Handsontable 插件,包括 npm 安装、基本配置和常用功能的实现。 ... [详细]
  • 本文介绍了如何使用Python爬取妙笔阁小说网仙侠系列中所有小说的信息,并将其保存为TXT和CSV格式。主要内容包括如何构造请求头以避免被网站封禁,以及如何利用XPath解析HTML并提取所需信息。 ... [详细]
  • 小程序的授权和登陆
    小程序的授权和登陆 ... [详细]
  • Cookie学习小结
    Cookie学习小结 ... [详细]
author-avatar
詹姵慧3482
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有