当前位置: 首页 > news >正文

[libos源码学习 1] Liboc协程生产者消费者举例

文章目录

    • 1. CoRoutineEnv_t结构体用于管理协程环境
  • 3 Liboc协程生产者消费者例子
  • 4 Liboc协程生产者消费者, 为什么队列不需要上锁?
  • 5. 两个协程访问资源不需要加队列吗
  • 5. 参考

1. CoRoutineEnv_t结构体用于管理协程环境

struct stCoRoutineEnv_t
{
stCoRoutine_t *pCallStack[ 128 ];
int iCallStackSize;
stCoEpoll_t *pEpoll;//for copy stack log lastco and nextco
stCoRoutine_t* pending_co;
stCoRoutine_t* occupy_co;};中文描述
stCoRoutineEnv_t结构体是用于协程环境的结构体,它包含了以下几个成员:1. pCallStack:这是一个数组,用于存储协程的调用栈。数组的大小是128,这意味着这个环境可以同时运行128个协程。2. iCallStackSize:这是一个整数,用于记录当前调用栈的大小,也就是正在运行的协程的数量。3. pEpoll:这是一个指向stCoEpoll_t结构体的指针,用于管理协程的事件循环。4. pending_co:这是一个指向stCoRoutine_t结构体的指针,用于表示待处理的协程,也就是在事件循环中等待执行的协程。5. occupy_co:这是一个指向stCoRoutine_t结构体的指针,用于表示当前被占用的协程,也就是正在执行的协程。

中文描述

stCoRoutineEnv_t结构体用于管理协程环境,包括协程的调用栈、调用栈的大小、事件循环以及正在执行和等待执行的协程。它的主要作用是提供一个运行协程的环境,协程可以在这个环境中进行切换,实现并发执行。

结构体成员详解

  • pCallStack:这是一个数组,用于存储协程的调用栈。数组的大小是128,这意味着这个环境可以同时运行128个协程。
  • iCallStackSize:这是一个整数,用于记录当前调用栈的大小,也就是正在运行的协程的数量。
  • pEpoll:这是一个指向stCoEpoll_t结构体的指针,用于管理协程的事件循环。事件循环是协程的核心,它负责管理协程的切换和调度。
  • pending_co:这是一个指向stCoRoutine_t结构体的指针,用于表示待处理的协程,也就是在事件循环中等待执行的协程。
  • occupy_co:这是一个指向stCoRoutine_t结构体的指针,用于表示当前被占用的协程,也就是正在执行的协程。

结构体的使用

stCoRoutineEnv_t结构体通常用于协程库或框架中,用于管理协程的运行环境。开发者可以使用这个结构体来创建、管理和调度协程,以实现并发执行。

struct stCoRoutine_t
{stCoRoutineEnv_t *env;pfn_co_routine_t pfn;void *arg;coctx_t ctx;char cStart;char cEnd;char cIsMain;char cEnableSysHook;char cIsShareStack;void *pvEnv;//char sRunStack[ 1024 * 128 ];stStackMem_t* stack_mem;//save satck buffer while confilct on same stack_buffer;char* stack_sp; unsigned int save_size;char* save_buffer;stCoSpec_t aSpec[1024];};

#2. stCoRoutine_t协程的实体
stCoRoutine_t结构体定义了一个协程的实体,包含了协程的环境、协程体、参数、上下文、标志位、堆栈内存以及特殊变量等信息。下面是对这个结构体的详细解释:

成员解释

env:指向stCoRoutineEnv_t结构体的指针,表示协程所在的环境。

pfn_co_routine_t pfn:指向协程体的函数指针,表示协程的主体逻辑。

*void arg:协程的参数,传递给协程体的参数。

coctx_t ctx:协程的上下文,用于保存协程的执行状态。

cStart, cEnd, cIsMain, cEnableSysHook, cIsShareStack:这些是字符类型的标志位,用于标记协程的特性,例如是否是主协程、是否启用系统钩子等。

*void pvEnv:未明确指定的环境指针,可能用于特定的协程环境。

stStackMem_t stack_mem*:指向stStackMem_t结构体的指针,用于管理协程的堆栈内存。运行是栈的结构,libco提供了两种方式,一个是每个协程拥有一个独立的栈,默认分配128KB空间,缺点是每个协程可能只用到了1KB不到,碎片较多。还有一种是共享栈模式,需要我们在创建协程的时候在Co_create中指定第二个参数,这种方法是多个协程共用一个栈,但是在协程切换的时候需要拷贝已使用的栈空间。

char stack_sp, unsigned int save_size, char save_buffer**:用于保存堆栈冲突时的堆栈缓冲区信息。

stCoSpec_t aSpec[1024]:一个数组,用于存储协程的特殊变量或特性。

结构体的使用
stCoRoutine_t结构体用于表示一个协程实体,包含了协程的环境、执行体、参数、上下文、标志位、堆栈管理以及特殊变量等信息。开发者可以使用这个结构体来创建、管理和调度协程,以实现并发执行。

3 Liboc协程生产者消费者例子

你提供的代码展示了如何使用协程(co-routine)在生产者-消费者模式下进行任务处理。下面是对代码的详细解释:1. 头文件包含:* #include <unistd.h>:POSIX标准的系统调用库。* #include <stdio.h>:标准输入输出库。* #include <stdlib.h>:标准库。* #include <queue>:C++标准库中的队列。* "co_routine.h":假设这是你自定义的协程库头文件。2. 任务结构体:struct stTask_t{int id;};stTask_t结构体用于表示任务,其中包含一个任务ID。3. 环境结构体:struct stEnv_t{stCoCond_t* cond;queue<stTask_t*> task_queue;};stEnv_t结构体用于表示协程环境,包含一个条件变量cond和一个任务队列task_queue。4. 生产者协程:void* Producer(void* args){co_enable_hook_sys();stEnv_t* env=  (stEnv_t*)args;int id = 0;while (true){stTask_t* task = (stTask_t*)calloc(1, sizeof(stTask_t));task->id = id++;env->task_queue.push(task);printf("%s:%d produce task %d\n", __func__, __LINE__, task->id);co_cond_signal(env->cond);poll(NULL, 0, 1000);}return NULL;}Producer函数是一个生产者协程,它不断地创建任务并将其放入任务队列中,然后通知消费者协程有新任务到达。co_enable_hook_sys()用于启用协程系统调用hook,co_cond_signal(env->cond)用于通知消费者协程有新任务到达,poll(NULL, 0, 1000)用于阻塞一段时间(1秒)。5. 消费者协程:void* Consumer(void* args){co_enable_hook_sys();stEnv_t* env = (stEnv_t*)args;while (true){if (env->task_queue.empty()){co_cond_timedwait(env->cond, -1);continue;}stTask_t* task = env->task_queue.front();env->task_queue.pop();printf("%s:%d consume task %d\n", __func__, __LINE__, task->id);free(task);}return NULL;}Consumer函数是一个消费者协程,它不断地从任务队列中取出任务并处理。co_cond_timedwait(env->cond, -1)用于在没有任务时等待,直到生产者协程通知有新任务到达。6. 主函数:int main(){stEnv_t* env = new stEnv_t;env->cond = co_cond_alloc();stCoRoutine_t* consumer_routine;co_create(&consumer_routine, NULL, Consumer, env);co_resume(consumer_routine);stCoRoutine_t* producer_routine;co_create(&producer_routine, NULL, Producer, env);co_resume(producer_routine);co_eventloop(co_get_epoll_ct(), NULL, NULL);return 0;}在main函数中,首先创建了一个协程环境env,然后分别创建了生产者和消费者协程,并使用co_resume函数启动它们。最后,使用co_eventloop函数进入事件循环,等待协程的执行完成。说明* 协程创建和启动:使用co_create和co_resume函数创建和启动协程。* 条件变量使用:生产者和消费者协程通过条件变量进行通信,生产者通知消费者有新任务到达。* 任务队列:使用C++标准库中的queue来管理任务队列。* 事件循环:使用co_eventloop函数进入事件循环,等待协程的执行完成。这个示例展示了如何使用协程实现生产者-消费者模式,通过条件变量和任务队列实现协程之间的通信和任务处理。

4 Liboc协程生产者消费者, 为什么队列不需要上锁?

在多线程环境中,使用队列而不需要显式上锁(锁定)主要依赖于以下几个因素:

  1. 线程局部存储(Thread Local Storage, TLS):在你的代码中,使用了__thread关键字来确保每个线程都有自己独立的gCoEnvPerThread变量副本。这意味着每个线程在访问stEnv_t结构体中的task_queue时,都会访问自己独立的队列副本,而不是共享的全局队列。因此,不需要显式上锁,因为每个线程只会影响自己的队列副本。

  2. 协程的特性:协程(co-routine)是一种轻量级的线程切换机制,它允许在多个函数之间切换执行,而不需要创建和销毁线程。协程的上下文切换开销比线程要小得多,因此可以更频繁地进行切换。由于协程的特性,协程之间的通信通常不需要复杂的锁机制,因为协程的上下文切换是快速且高效的。

  3. 条件变量的使用:在生产者-消费者模式中,条件变量用于在生产者和消费者之间进行通信。当生产者向条件变量发送信号时,消费者会在等待中被唤醒,从而避免了在队列上进行显式的锁定。条件变量的使用确保了生产者和消费者之间的同步,而不需要显式的锁机制。

  4. 队列的线程安全性:C++标准库中的queue默认不是线程安全的,但在你的代码中,task_queue是stEnv_t结构体的一部分,而stEnv_t是每个线程的独立副本。因此,每个线程对task_queue的操作都是线程安全的,不需要额外的锁机制。

然而,虽然在你的代码中没有显式上锁,但在多线程环境中,仍然需要确保每个线程对共享资源的访问是线程安全的。在上述代码中,这通过__thread关键字和stEnv_t结构体的独立副本实现。

总之,使用__thread关键字和条件变量,结合协程的特性,使得在生产者-消费者模式中可以避免显式上锁,从而提高了代码的效率和可读性。

5. 两个协程访问资源不需要加队列吗

在你的代码中,虽然两个协程(生产者和消费者)访问task_queue时没有显式地使用锁(如std::mutex),但这并不意味着没有进行资源保护。这里的关键在于__thread关键字和协程的特性。

  • _THREAD关键字的作用

__thread关键字用于在多线程环境中为每个线程提供独立的变量副本。因此,当你在全局作用域中定义gCoEnvPerThread变量时,__thread关键字确保了每个线程都有自己独立的stEnv_t结构体副本,包括其中的task_queue。这意味着每个线程在访问task_queue时,都会访问自己独立的队列副本,而不是共享的全局队列。因此,不需要显式上锁,因为每个线程只会影响自己的队列副本。

  • 协程的特性

协程是一种轻量级的线程切换机制,它允许在多个函数之间切换执行,而不需要创建和销毁线程。协程的上下文切换开销比线程要小得多,因此可以更频繁地进行切换。由于协程的特性,协程之间的通信通常不需要复杂的锁机制,因为协程的上下文切换是快速且高效的。

  • 条件变量的使用

在生产者-消费者模式中,条件变量用于在生产者和消费者之间进行通信。当生产者向条件变量发送信号时,消费者会在等待中被唤醒,从而避免了在队列上进行显式的锁定。条件变量的使用确保了生产者和消费者之间的同步,而不需要显式的锁机制。

  • 线程安全性

虽然在你的代码中没有显式上锁,但在多线程环境中,仍然需要确保每个线程对共享资源的访问是线程安全的。在上述代码中,这通过__thread关键字和stEnv_t结构体的独立副本实现。每个线程对task_queue的操作都是线程安全的,因为每个线程都有自己独立的stEnv_t结构体副本。

总之,使用__thread关键字和条件变量,结合协程的特性,使得在生产者-消费者模式中可以避免显式上锁,从而提高了代码的效率和可读性。然而,这并不意味着没有进行资源保护,而是通过__thread关键字和协程的特性实现了线程安全。

5. 参考

https://blog.csdn.net/weixin_43705457/article/details/106863859

相关文章:

[libos源码学习 1] Liboc协程生产者消费者举例

文章目录 1. CoRoutineEnv_t结构体用于管理协程环境 3 Liboc协程生产者消费者例子4 Liboc协程生产者消费者&#xff0c; 为什么队列不需要上锁&#xff1f;5. 两个协程访问资源不需要加队列吗5. 参考 1. CoRoutineEnv_t结构体用于管理协程环境 struct stCoRoutineEnv_t { stCo…...

Python OpenCV 图像改变

更改图像数据 通过 改像素点 或者 切片的区域 import cv2 import numpy as np img cv2.imread("image.jpg") print(img[3,5]) # 显示某位置(行3列5)的像素值( 如 [53 34 29] 它是有三通道 B G R 组成) img[3,5] (0,0,255) # 更改该位置的像素…...

k8s按需创建 PV和创建与使用 PVC

在 Kubernetes 中&#xff0c;PersistentVolume&#xff08;PV&#xff09;和 PersistentVolumeClaim&#xff08;PVC&#xff09;用于管理存储资源。PV 是集群中的存储资源&#xff0c;而 PVC 是 Pod 请求 PV 的方式。按需创建 PV 通常使用 StorageClass 实现动态存储分配&…...

揭秘云计算 | 2、业务需求推动IT发展

揭秘云计算 | 1、云从哪里来&#xff1f;-CSDN博客https://blog.csdn.net/Ultipa/article/details/143430941?spm1001.2014.3001.5502 书接上文&#xff1a; 过去几十年间IT行业从大型主机过渡到客户端/服务器&#xff0c;再过渡到现如今的万物互联&#xff0c;IT可把控的资…...

【系统面试篇】进程与线程类(2)(笔记)——进程调度、中断、异常、用户态、核心态

目录 一、相关面试题 1. 进程的调度算法有哪些&#xff1f; 调度原则 &#xff08;1&#xff09;先来先服务调度算法 &#xff08;2&#xff09;最短作业优先调度算法 &#xff08;3&#xff09;高响应比优先调度算法 &#xff08;4&#xff09;时间片轮转调度算法 &am…...

基于MySQL的企业专利数据高效查询与统计实现

背景 在进行产业链/产业评估工作时&#xff0c;我们需要对企业的专利进行评估&#xff0c;其中一个重要指标是统计企业每一年的专利数量。本文基于MySQL数据库&#xff0c;通过公司名称查询该公司每年的专利数&#xff0c;实现了高效的专利数据统计。 流程 项目流程概述如下&…...

热成像手机VS传统热成像仪:AORO A23为何更胜一筹?

热成像技术作为一种非接触式测温方法&#xff0c;广泛应用于石油化工巡检、电力巡检、应急救援、医疗、安防等“危、急、特”场景。提及热成像设备&#xff0c;人们往往会首先想到价格高昂、操作复杂且便携性有限的热成像仪。但是&#xff0c;随着技术的不断进步&#xff0c;市…...

Spring IoC——依赖注入

1. 依赖注入的介绍 DI&#xff0c;也就是依赖注入&#xff0c;在容器中建立的 bean &#xff08;对象&#xff09;与 bean 之间是有依赖关系的&#xff0c;如果直接把对象存在 IoC 容器中&#xff0c;那么就都是一个独立的对象&#xff0c;通过建立他们的依赖关系&#xff0c;…...

Linux 中,flock 对文件加锁

在Linux中&#xff0c;flock是一个用于对文件加锁的实用程序&#xff0c;它可以帮助协调多个进程对同一个文件的访问&#xff0c;避免出现数据不一致或冲突等问题。以下是对flock的详细介绍&#xff1a; 基本原理 flock通过在文件上设置锁来控制多个进程对该文件的并发访问。…...

CentOS下载ISO镜像的方法

步骤 1&#xff1a;访问CentOS官方网站 首先&#xff0c;打开浏览器&#xff0c;输入CentOS的官方网站地址&#xff1a;Download 在网站上找到ISO镜像的下载链接&#xff0c;通常位于“Downloads”或类似的页面上。 选择所需的CentOS版本和架构&#xff08;如x86_64&#xf…...

Node.js 入门指南:从零开始构建全栈应用

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;node.js篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来node.js篇专栏内容:node.js-入门指南&#xff1a;从零开始构建全栈应用 前言 大家好&#xff0c;我是青山。作…...

MYSQL 真实高并发下的死锁

https://pan.baidu.com/s/1nM3VQdbkNZhnK-wWboEYxA?pwdvwu6 下面是风控更新语句 ------------------------ LATEST DETECTED DEADLOCK ------------------------ 2023-08-04 01:00:10 140188779017984 *** (1) TRANSACTION: TRANSACTION 895271870, ACTIVE 0 sec starting …...

Zookeeper 简介 | 特点 | 数据存储

1、简介 zk就是一个分布式文件系统&#xff0c;不过存储数据的量极小。 1. zookeeper是一个为分布式应用程序提供的一个分布式开源协调服务框架。是Google的Chubby的一个开源实现&#xff0c;是Hadoop和Hbase的重要组件。主要用于解决分布式集群中应用系统的一致性问题。 2. 提…...

设计模式之结构型模式---装饰器模式

目录 1.概述2.类图3.应用场景及优缺点3.1 应用场景3.2 优缺点3.2.1 优点3.2.2 缺点 4.实现4.1 案例类图4.2 代码实现4.2.1 定义抽象构建角色4.2.2 定义具体构建角色4.2.3 定义抽象装饰器角色4.2.4 定义具体装饰角色4.2.5 装饰器模式的使用 1.概述 装饰器模式是指在不改变现有对…...

Android Pair

Pair在Android中是一种轻量级的工具类&#xff0c;并不是严格意义上的数据结构。 数据结构是一组有组织的方式来存储和管理数据的方式&#xff0c;如数组、链表、栈、队列、树、图等&#xff0c;它们有自己的特性和操作规则。而Pair更像是一个简单的封装&#xff0c;用于在需要…...

华为荣耀曲面屏手机下面空白部分设置颜色的方法

荣耀部分机型下面有一块空白区域&#xff0c;如下图红框部分 设置这部分的颜色需要在themes.xml里面设置navigationBarColor属性 <item name"android:navigationBarColor">android:color/white</item>...

《C#语法一篇通》,有20万字,需8MB字节,宜48小时阅读,没准会继续完善

本文摘录了C#语法的主要内容&#xff0c;接近20万字。 所有鸡汤的味道都等于马尿&#xff01; 如果你相信任何所谓的鸡汤文章&#xff0c;智商堪忧。 计算机语言没有”好不好“之说&#xff0c;骗子才会告诉你哪个语言好&#xff0c;学好任何一本基础语言&#xff08;C&#…...

嵌入式硬件工程师的职业发展规划

嵌入式硬件工程师可以按照以下阶段进行职业发展规划&#xff1a; 1. **初级阶段&#xff08;1-3 年&#xff09; ** - **技术学习与积累**&#xff1a; **电路基础强化**&#xff1a; 深入学习模拟电路和数字电路知识&#xff0c;能够熟练分析和设计基本的电路&#xff0c;…...

QT for android 问题总结(QT 5.15.2)

1.配置好的sdk&#xff0c;显示设置失败 Android SDK Command-line Tools run. Android Platform-Tools installed. Command-line Tools (latest) 版本过高导致报错 &#xff0c;下载一个低版本的latest &#xff0c;替换掉之前latest中的文件。即可&#xff0c;latest 路径如…...

PyTorch实战-手写数字识别-MLP模型

1 需求 包懂&#xff0c;40分钟掌握PyTorch深度学习框架&#xff0c;对应神经网络算法理论逐行讲解用PyTorch实现图像分类代码_哔哩哔哩_bilibili 10分钟入门神经网络 PyTorch 手写数字识别_哔哩哔哩_bilibili pytorch tutorial: PyTorch 手写数字识别 教程代码 从零设计并训…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...