搜索
bottom↓
回复: 10

轻量级多线程protothread及类C++编程方法的代码(VC测试下测试通过,附源码)。

[复制链接]

出0入0汤圆

发表于 2010-6-4 13:45:06 | 显示全部楼层 |阅读模式
轻量级多线程protothread及类C++编程方法的代码 , 用纯C达到类似多线程和C++编程的效果。
这是我学习单片机编程中的一点测试,希望和大家交流一下。

1)把protothread移植到vc里面,方便调试。

2)自己实现了一个用纯C语言达到类似C++编程语法的原型。具有C++编程的风格,但又有良好的可移植性。

本实验在VC测试下测试通过,附源码。


//vc source code--------------

// 1.cpp : Defines the entry point for the console application.
//
//#include <stdio.h>
//#include <stdlib.h>

#include <iostream>
#include "stdafx.h"

#include "pt_type.h"
#include "pt_config.h"
#include "pt.h"
#include "pt_ex.h"
#include "pt_timer.h"
#include "pt-sem.h"
#include "lc.h"

#include <windows.h>

extern void SIGNAL();


PT_TMR_Create(tmr1);
PT_TMR_Create(tmr2);
PT_TMR_Create(tmr3);
PT_TMR_Create(tmr4);

PT_TSK_Create(protothread1);
PT_TSK_Create(protothread2);
PT_TSK_Create(protothread3);
PT_TSK_Create(protothread4);

//--------------------------------------------------------------------
#define INIT_MyClass(x)   {x.init=MyClass_init; x.me=&x; x.init(&x);}

struct MyClass;
struct MyClass {
  int id;
  struct MyClass *me;
  void (*init)(struct MyClass *me);
  void (*disp)(struct MyClass *me);
};

void MyClass_disp(struct MyClass* me){
           char buf[20];
         sprintf(buf,"I am Object%i \r\n",me->id);
         printf(buf);                  
}

void MyClass_init(struct MyClass *me){
        me->disp= MyClass_disp;
}
//-----------------------------------------------------------
struct MyClass o1,o2,o3,o4;

void MyTicket()
{
        int j,k,a,b;
        //putchar('\a');
        Sleep(1);
    SIGNAL();
}

unsigned char protothread1(struct pt *pt)
{
  PT_BEGIN(pt);
  while(1)
  {   
      PT_TimerSet(&tmr1, 3000);
      PT_WAIT_UNTIL(pt, PT_TimerExpired(&tmr1));
//          printf("Hello World 1!\n");
          o1.disp(&o1);
  }
  PT_END(pt);
}

unsigned char protothread2(struct pt *pt)
{
  PT_BEGIN(pt);
  while(1)
  {
      PT_TimerSet(&tmr2, 2000);
      PT_WAIT_UNTIL(pt, PT_TimerExpired(&tmr2));
//          printf("Hello World 2!\n");
          o2.disp(&o2);
  }
  PT_END(pt);
}

unsigned char protothread3(struct pt *pt)
{
  PT_BEGIN(pt);
  while(1)
  {
      PT_TimerSet(&tmr3, 200);
      PT_WAIT_UNTIL(pt, PT_TimerExpired(&tmr3));
//          printf("Hello World 3!\n");
          o3.disp(&o3);
  }
  PT_END(pt);
}

unsigned char protothread4(struct pt *pt)
{
  PT_BEGIN(pt);
  while(1)
  {
      PT_TimerSet(&tmr4, 400);
      PT_WAIT_UNTIL(pt, PT_TimerExpired(&tmr4));
//          printf("Hello World 4!\n");
          o4.disp(&o4);
  }
  PT_END(pt);
}


int main(int argc, char* argv[])
{
        printf("Hello World!\n");
       
        int i;
        INIT_MyClass(o1);
        INIT_MyClass(o2);
        INIT_MyClass(o3);
        INIT_MyClass(o4);

        o1.id=1;
        o2.id=2;
        o3.id=3;
        o4.id=4;

    PT_INIT(&PT_TCB(protothread1));
    PT_INIT(&PT_TCB(protothread2));
    PT_INIT(&PT_TCB(protothread3));
    PT_INIT(&PT_TCB(protothread4));
   
    while(1) {
                if (i<2) MyTicket();
                else{
                        i=0;
                        protothread1(&PT_TCB(protothread1));
                        protothread2(&PT_TCB(protothread2));               
                        protothread3(&PT_TCB(protothread3));
                        protothread4(&PT_TCB(protothread4));               
                }         
                i++;
        }
        return 0;
}

//---- 运行效果:

(原文件名:1.GIF)

//源代码包:
点击此处下载

出0入0汤圆

发表于 2010-6-4 14:09:50 | 显示全部楼层
如果LZ想介绍ProtoThread的话,最好详细介绍一下这么干的目的,实现方法,好处和坏处。
在Contiki的一个PDF文档有,不过翻译工作会比较辛苦。

而且,这个范例代码没有非常明显的表现出来Yield Point。

简单来说,ProtoThread和FreeRTOS等的CoRoutine是类似的实现方法,实际应用上,限制很明显。

出0入0汤圆

发表于 2010-6-4 14:22:54 | 显示全部楼层
回复【1楼】dr2001
-----------------------------------------------------------------------

能具体说一下“CoRoutine”具体有哪些限制?

出0入0汤圆

发表于 2010-6-6 01:41:22 | 显示全部楼层
coroutine和真正的thread的区别挺多,但是也不好说是限制,须知Contiki的使用环境
是传感器网络节点,一般来说,大都是内存极其受限,相比之下,CPU资源是可以不那么
受限的(或者这么说,CPU工作时间长些仅仅是影响节点的寿命,而RAM不够用则节点根本
不可能工作起来)。

protothread就是为了解决这个多线程会消耗过多的RAM的问题而用增加CPU处理工作来做交换。

每个函数(protothread)在yield的时候都完全返回,也就是相当于多个“线程”共用同一个
堆栈。但是这和event-based的系统(比如tinyos)的区别在于,这个系统编程的时候你还是
可以认为是顺序执行的(yield之后如果继续执行的话,不是从函数开头而是从上次yield的
地方继续执行),event-based的系统则必须人为将系统拆分成许多event(简单的理解,你可
以认为就是把程序全写成状态机的形式,很多情况来说,这对人来说不是一个很好驾驭的
模型,比如我们会很习惯做了这个时候干什么,条件没成熟就继续做什么;可是要弄成状
态机形式,你就必须自己分成几个状态,弄出状态转移图,而用这种类似thread的protothread
则不需要显式地体现出来你的状态机)。

至于protothread(coroutine和它本质一样)的限制,取决于实现,如果使用可移植的switch来实现,
那么限制超多,不能用switch了;如果使用GNU的computed goto来实现,则没有这个限制;
但是不管是什么实现,都需要注意,如果你希望函数的auto变量保存上次的值的话,必须声明成
static,这才是这类在C语言中实现coroutine类机制的本质限制。

这些东西,说到最后就是一个continuation的概念,只不过在函数式编程社区以外都不怎么用这个
概念而已。

上面关于protothread的说得可能过于泛泛,如果想知道详情,还是应该读这篇论文:
Protothreads: Simplifying Event-Driven Programming of Memory-Constrained Embedded Systems
Adam Dunkels, Oliver Schmidt, Thiemo Voigt, Muneeb Ali

出0入0汤圆

发表于 2010-6-6 10:06:50 | 显示全部楼层
minux解答的很详细啊。盛赞一下。

补充一点点:
Protothread或者叫Coroutine,主要就是提供continuation point。即函数从yield返回后,下次调用会接着yeild的下一句执行。目的之一是简化代码结构,增强可读性。当然,Iterator这样的东西也可以比较方便的实现。

coroutine可以是有自己独立堆栈的(Thread的协调多任务用法),也可以是共享堆栈的。共享堆栈就是如freertos/coroutine,protothread这样的实现。好处是节约内存;最大劣势是共享堆栈,因此所有栈自动变量在yield会丢失。
解决办法要么是用static/全局变量,不在栈上保存,但是可能丢失重入特性(是否丢看实现手段);要么用malloc之类的使用堆,但存在内存泄漏(典型为Yield之后Reset),内存碎片的问题(malloc自身,决定于其算法)。

实现手段上,符合标准,可移植的,是基于switch的实现。为了使coroutine可用并且好用,至少仰赖于以下C标准的规定,或者C标准中没有说,但是经讨论,是合法描述的情形:
- 宏展开后,宏中的代码都在一个物理行上。
- switch的case可以和for/if之类的语句嵌套。即switch(bbb) { for(xx; xx; xx) { case 1: ... ; case 2: yyy} }是合法的。
第二条是switch实现的核心,如果有变化,就over。

标准switch实现的坏处:
- switch必须谨慎使用:嵌入的switch中间不能带yield,(return,exit看实现)之类的返回点。这个可以用if/else避免。
- switch靠后的continuation point的调用一次额外开销比较大,要一个一个比较过去。

使用嵌入汇编,GNU的label,computed goto等实现,限制要少,效率也高。问题一个是可移植;另外一个是编译器优化是否导致问题,嵌入式汇编这个很明显,GNU的我没用过,没体会。

出0入264汤圆

发表于 2010-6-6 10:16:04 | 显示全部楼层
谢谢,但是源码好像没有传上来。

出0入0汤圆

发表于 2012-5-27 11:01:01 | 显示全部楼层
mcu_lover 发表于 2010-6-6 10:16
谢谢,但是源码好像没有传上来。

源码好像没有传上来

出0入0汤圆

发表于 2012-7-14 21:03:29 | 显示全部楼层
源码好像没有传上来

出0入0汤圆

发表于 2013-8-2 22:17:01 | 显示全部楼层
Protothreads

出0入0汤圆

发表于 2014-3-27 12:11:22 | 显示全部楼层
'K L       code

出0入0汤圆

发表于 2014-3-28 20:18:28 来自手机 | 显示全部楼层
学习一下                 
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-1 08:05

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表