基于SylixOS的高效生产者消费者模型编程应用设计

来源 :科学与财富 | 被引量 : 0次 | 上传用户:aaronqi666
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘 要:在SylixOS下,介紹了基于传统消息队列和高效协程模式两种生产者-消费者模型的编程方法,比较两种模式的编程方法在互斥和同步机制上的区别及其带来的消耗。
  关键词:SylixOS;同步和互斥;协程
  中图分类号:TP311.1            文献标识码:A
  引言:
  传统的生产者-消费者模型中,生产者和消费者之间的关系可以总结为如下几点:
  ●生产者与生产者:互斥关系
  ●消费者与消费者:互斥关系
  ●生产者与消费者:互斥与同步关系
  要处理好这些关系,就要用到系统中的互斥与同步机制,并涉及到线程的阻塞和唤醒操作,而这些机制往往会带来一些必要的消耗,影响运行效率。
  协程,又称作协同程序,是比线程还小的可执行代码序。在SylixOS中,一个线程可以拥有多个协程,这些协程共享了线程除了栈以外的所有资源,包括优先级、内核对象等。线程内部的协程不可被抢占,只能轮转运行。所以,利用这个特点可以构建出一个基于协程的高效的生产者-消费者模型。
  1、何为生产者消费者模型
  经典生产者-消费者模型描述如下:两个线程共享一个消息队列,其中一个线程,即生产者,向该消息队列中放入信息;另外一个线程,即消费者,从该消息队列中取走信息,这里就涉及到了多任务操作系统中的同步和互斥机制。
  在SylixOS中,同步即一个任务的执行结果是另一个任务能够执行的前提条件,互斥即多任务同时使用到临界资源时可能会引发的竞争。在生产者-消费者模型中,消费者任务需要等待生产任务产生数据后才能执行,即同步;而生产任务和消费任务要串行地访问消息队列,即互斥。
  2、生产者消费者模型的两种编程方法
  2.1 传统消息队列方式
  该方式中,生产者-消费者模型中的公共缓冲区即对应着消息队列。编程步骤如下:
  ① 创建生产者线程;
  ② 创建消费者线程;
  ③ 创建消息队列,获取操作句柄;
  ④ 生产者线程中循环调用消息发送函数,向消息队列中发送数据;
  ⑤ 消费者线程中循环调用消息接收函数,从消息队列中获取数据,若消息队列中无数据,则会阻塞。
  2.2 高效率协程模式
  SylixOS中的协程需要依赖所属线程被调度时执行,所以需要先创建一个初始线程,再去调用相应的函数创建生产者和消费者协程,需要注意的是,每一个线程创建时都会默认创建一个初始协程,并且线程总是从该初始协程开始运行,所以初始线程中需要主动放弃处理器,以保证生产者和消费者协程能运行。编程步骤如下:
  ① 创建初始线程;
  ② 创建生产者协程;
  ③ 创建消费者协程;
  ④ 初始线程放弃处理器调用;
  ⑤ 生产者协程向公共缓冲区填充消息后,主动放弃处理器;
  ⑥ 消费者协程从公共缓冲区获取消息后,主动放弃处理器;
  ⑦ 初始线程恢复生产者和消费者协程,跳转至步骤⑤。
  2.3 两种编程模式的比较
  通过上述两种模式的步骤比较,可以得出以下结论:
  ① 传统消息队列模式中,需要创建多线程并进行线程间的切换,同时生产者和消费者线程间的通信采用消息队列的形式,其发送和接收函数内部实现涉及到进入和退出内核态的模式切换,以保证生产者和消费者线程中的同步和互斥机制,这里面会有较大的时间消耗;
  ② 高效协程模式中,只有一个初始线程,内部的协程并不会被调度器调度,所以不会有线程切换的消耗。另外,初始线程内部的协程是以轮转的方式运行,由用户程序自行管理,所以也就不会有线程间通信带来的消耗。
  综上,可以看出,协程模式比传统消息队列模式更高效。
  3、模型编程流程设计
  基于两种方法设计应用流程图及其简单说明
  3.1 消息队列方法
  3.2 协程方法
  4、代码设计
  4.1 消息队列方法
  基于消息队列的设计代码中,生产者线程获取当前时间t1并填入消息队列中,消费者线程从消息队列中获取消息后再次获取当前时间t2,将t1和t2的差值作为该方法带来的时间消耗。示例代码如下。
  #include <stdio.h>
  #include <stdlib.h>
  #include <pthread.h>
  #include <time.h>
  #define MAX_MSG_COUNT   100
  #define MAX_MSG_BYTES   sizeof(struct timeval)
  LW_HANDLE   _G_hMsgQ = 0;
  static PVOID __threadConsume (PVOID  pvArg)
  {
   struct timeval  end;
   struct timeval  recv;
   INT    iError  = PX_ERROR;
   double t       = 0;
   size_t stLen   = 0;    INT    iMsgCnt = 0;
   while (1) {
   lib_memset(&end, 0, sizeof(struct timeval));
   lib_memset(&recv, 0, sizeof(struct timeval));
   iError = Lw_MsgQueue_Receive(_G_hMsgQ,
  (PVOID)&recv,
  sizeof(struct timeval),
  &stLen,
  LW_OPTION_WAIT_INFINITE);
   if (ERROR_NONE != iError) {
   printf("msg recv error.\n");
   break;
   }
   lib_gettimeofday(&end, LW_NULL);
   t += end.tv_sec * 1e6 + end.tv_usec - (recv.tv_sec * 1e6 + recv.tv_usec);
   if (++iMsgCnt == 100) {
  printf("legancy msgQ: consumer get msg cost: %.02f us\n", t / iMsgCnt);
   iMsgCnt = 0;
   t       = 0;
   }
   }
   return  (LW_NULL);
  }
  static PVOID __threadProduct (PVOID  pvArg)
  {
   struct timeval  start;
   INT             iError;
   while (1) {
   lib_memset(&start, 0, sizeof(struct timeval));
   lib_gettimeofday(&start, LW_NULL);
   iError = Lw_MsgQueue_Send(_G_hMsgQ, (PVOID)&start, sizeof(struct timeval));
   if (ERROR_NONE != iError) {
   printf("msg send error.\n");
   break;
   }
   Lw_Time_Sleep(1);
   }
   return  (LW_NULL);
  }
  int main (int argc, char **argv)
  {
   LW_HANDLE  hProduct;
   LW_HANDLE  hConsume;
   _G_hMsgQ = Lw_MsgQueue_Create("msg_cp",
   MAX_MSG_COUNT,
   MAX_MSG_BYTES,
  LW_OPTION_WAIT_FIFO | LW_OPTION_OBJECT_LOCAL,
   LW_NULL);
   hProduct = Lw_Thread_Create("t_product", __threadProduct, LW_NULL, LW_NULL);
   if (LW_OBJECT_HANDLE_INVALID == hProduct) {
   printf("t_product create failed.\n");
   return  (-1);
   }
   hConsume = Lw_Thread_Create("t_consume", __threadConsume, LW_NULL, LW_NULL);
   if (LW_OBJECT_HANDLE_INVALID == hConsume) {
   printf("t_consume create failed.\n");
   return  (-1);
   }
   Lw_Thread_Join(hProduct, LW_NULL);
   Lw_Thread_Join(hConsume, LW_NULL);
   Lw_MsgQueue_Delete(&_G_hMsgQ);
   return  (0);
  }
  4.2 协程方法
  基于協程的设计代码中,生产者协程将数据放入公共缓冲区,并获取当前时间t1,然后放弃CPU,接着消费者协程中获取时间t2,并从公共缓冲区获取数据,将t1和t2的差值作为生产者和消费者协程切换的时间消耗。示例代码如下。
  #include <SylixOS.h>
  #include <stdio.h>
  static PVOID  pcCrcb0 = LW_NULL;   static PVOID  pcCrcb1 = LW_NULL;
  static double t       = 0;
  static INT    iCnt    = 0;
  static struct timeval  start;
  static struct timeval  end;
  VOID  coroutine0 (PVOID  pvArg)
  {
   while (1) {
   lib_memset(&start, 0, sizeof(struct timeval));
   lib_gettimeofday(&start, LW_NULL);
   Lw_Coroutine_Yield();
   }
  }
  VOID  coroutine1 (PVOID  pvArg)
  {
   while (1) {
   lib_memset(&end, 0, sizeof(struct timeval));
   lib_gettimeofday(&end, LW_NULL);
   t += end.tv_sec * 1e6 + end.tv_usec - (start.tv_sec * 1e6 + start.tv_usec);
   if (++iCnt == 100) {
   printf("coroutine: consumer get msg cost: %.02f us\n", t / iCnt);
   iCnt = 0;
   t    = 0;
   }
   Lw_Coroutine_Yield();
   }
  }
  PVOID  tTest (PVOID  pvArg)
  {
   pcCrcb0 = Lw_Coroutine_Create(coroutine0, 2 * 1024, LW_NULL);
   if (pcCrcb0 == LW_NULL) {
   return  (LW_NULL);
   }
   pcCrcb1 = Lw_Coroutine_Create(coroutine1, 2 * 1024, LW_NULL);
   if (pcCrcb1 == LW_NULL) {
   return  (LW_NULL);
   }
   Lw_Coroutine_Yield();                    /*  使其他協程运行             */
   while (1) {
   Lw_Coroutine_Resume(pcCrcb0);
   Lw_Time_Sleep(1);
   }
   return  ((PVOID)1);
  }
  int main (int argc, char *argv[])
  {
   LW_HANDLE  hId;
   hId = Lw_Thread_Create("t_test", tTest, LW_NULL, LW_NULL);
   if (hId == LW_HANDLE_INVALID) {
   return  (PX_ERROR);
   }
   Lw_Thread_Join(hId, LW_NULL);
   return  (ERROR_NONE);
  }
  5、测试验证
  5.1 环境搭建
  硬件环境:
  ● CPU:Intel(R) Core(TM) i3-6100 CPU @ 3.70GHz
  ● 内存:4GB
  ● 硬盘:500GB
  软件环境
  ● SylixOS内核版本:1.9.9-9
  ● SylixOS BSP版本:1.1.3
  5.2 测试输出
  ① 传统消息队列模式
  ② 高效协程模式
  5.3 测试分析
  根据代码运行结果,可以看出生产者-消费者模型中,采用协程模式比传统消息队列模式时间消耗要小得多。
  6、结语
  在嵌入式领域的资源受限,生产消费模型简单情况下,使用高效协程编程可以有效降低传统消息队列模式下同步和互斥机制、线程调度等带来的时间消耗,提高生产者和消费者的运行效率。SylixOS内核原生支持协程,而不是使用第三方库模拟,使得SylixOS内部的协程管理更加便捷高效,这样使用SylixOS协程构建的生产者-消费者模型也就更加高效。
  参考文献:
  [1] 陈莉君. Linux内核编程[M]. 北京:机械工业出版社,2004
  [2] 刘俞. Linux多线程的互斥与同步控制及实践. 电脑知识与技术[J]. 2005,(18)
  [3] 曹聪,范廉明. 操作系统原理与分析. 科学出版社[M]. 2003,09
其他文献
摘 要:随着科技的进步,多种多样的新技术应用于各个领域。电气自动化控制系统是截止到现在人们普遍关心的焦点问题之一。就传统的电气自动化控制系统而言,需要多种连接线才能实现设备的连接和处理,这一过程极大地损耗了人力物力资源,同时也增加了资本的投入成本,给管理带来了麻烦。定期维护连接线,预防解决各种突发故障,诸如线路短路等,给系统本身的正常运行增加了难度,还一定程度上地影响了生产效率。  关键词:PLC
期刊
摘 要:随着人类社会的发展,在当今这个更加重视效率的时代,微波炉不需人类照看的烹饪过程无疑已经在人们的日常生活中起到了至关重要的作用。但简单的微波炉在日常生活中很难满足人们的需要,它不能按照需求来自由地控制人们对不同烹饪食品的需求而且也不能自由地控制烹饪时间,僵硬的操作方法经常会让食物没有煮熟或者过热,达不到人们的预期效果。微波炉的改善得到了人们的重视,本文将对微波炉变频器控制电路进行研究。  关
期刊
摘 要:10kv是连接用户和变电站之间的重要枢纽,其运行质量的好坏在一定程度上影响着整个系统的稳定性。笔者认为,加强电网系统的安全性和稳定性,需要做好10KV配电线路的相关检查和检修工作。本文针对10kV配电线路的相关内容进行分析,并针对检测内容和存在问题提出了一些整改建议,希望能够为优化10kV配电线路建设提供参考建议。  关键词:10kV配电线路;状态监测;检修技术  随着我国架空线路的不断增
期刊
摘 要:在电网中的电压质量受无功补偿系统的影响,同时电网的经济运行还受无功补偿系统的影响。本文首先对电网无功补偿的必要性进行叙述,然后对无功补偿国内外发展现状进行阐述,并对电网无功补偿设备进行了详细的介绍。  关键词:电网;无功补偿;研究现状;设备  1.无功补偿的必要性  电网低压配电是通过厂用变将10KV变成400V,然后通过低压配电系统,给用电设备提供电源,驱动动力设备工作的,动力设备多为感
期刊
摘 要:近几年来,我国科学技术的研发和应用不断繁荣与进步,也在很大程度上促进了各个产业的有效拓展。在这样的情况之下,积极利用当前大背景之下的相关技术,对各个产业进行系统的推进是非常重要的。本文主要研究的是计算机嵌入式实时操作系统的相关内容,不断加强这一技术的应用和设计,可以更好地推动我国科学技术的有效繁荣与进步。因此,针对这种发展特点,为了更好地促进相关企业的不断发展,积极加强计算机嵌入式实时操作
期刊
摘 要:新时期,智能建筑是现代建筑产业发展的重要产物,其是一种和社会发展要求相符、和人们生活相符的新型建筑。当前,伴随着人们生活质量的不断提高,智能建筑设计和人们的基本居住要求更为契合。为打造更为完善的智能建筑系统,必须要配备优质的机电设备,满足人们对机电设备的要求,以提高人们的生活质量。基于此,本文就智能建筑机电设备自动化技术展开了分析与研究。  关键词:智能建筑;机电设备;自动化  为顺应时代
期刊
摘 要:随着经济的不断发展,各行各业竞争不断,各行各业服务体验都在创新,希望给顾客更好的体验,提高自己的竞争力,而互联网电力服务创新也不可避免。电网企业则需要建立面向市场竞争和互联网模式的新型营销服务体系,为电网客户提供更好、更便捷的服务,取得电网客户的信任,实现双赢的局面。“互联网+电力营销”这种模式并不是简单的上网服务,而是融入了互联网等一系列优势的服务,这种服务模式以市场为主导,利用互联网的
期刊
摘 要:随着建筑行业的不断发展,在建筑行业中,电气安装工程属于十分重要的一个工程,同时也是一个较为复杂的工程。现今来看,在建筑工程建设安装中,电气安装工程占有的比例很大,同时也会直接影响到整个工程的施工进度、成本以及相关的质量环节。因此相关的管理人员在进行现场施工中,必须要加强管理,能够落实监督工作,从而来保证建筑电气安装的质量。本文主要是对建筑电气安装管理技术进行了分析,提出了相关的建议。  关
期刊
摘 要:随着BIM在国内的发展以及创新创业环境的形成,市场和企业对于BIM人才的需求越来越大。基于此,研究提出开设BIM+专业课程、开展BIM服务反哺教学等途径,探索工程造价专业实践教学的创新模式,培养具有BIM技术应用及创新创业能力的新型造价人才。  关键词:BIM;教学改革;工程造价  BIM作为一种新型建筑信息化技术是当今建筑行业的总体发展趋势,被视为继 CAD 之后建筑业的“第二次革命”,
期刊
摘 要:我国目前常用的化工工艺而言,其中大部分化工产品生产工艺具有连续操作性强、操作流程复杂、操作内容繁琐、安全隐患突出的特点,同时这些产品还有着毒、有害、易燃、易爆及高腐蚀特征,其在生产中一旦出现疏忽和错误操作,不仅会给生产企业带来利益损害,甚至会造成工作人员伤亡事故。本文就化工工艺的风险识别与安全评估做了简单的探讨。  关键词:化工工艺;风险识别;安全评价;隐患  化工生产本身就是一个复杂、繁
期刊