加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

c++协程

(2016-08-09 16:55:45)
标签:

it

分类: 进阶1

协程与多线程的区别:协程只有一个线程。

协程与普遍函数调用区别:协程会记录函数的执行状态,挂起再恢复会从挂起的状态执行起。

协程是一种能记录函数执行状态的函数调用。

 

先看一段代码吧,代码来源博客http://www.yeolar.com/note/2013/02/17/coroutines/

int function(void)
{
     static int i, state = 0;
     switch (state)
     {
        case 0:   // start of function
        for (i = 0; i < 10; i++)
        {
             state = 1;    // so we will come back to LABEL1
             return i;
            case 1: ;       // resume control straight after the return
        }
    }
}

调用很简单:

printf("%d  ", function());

printf("%d  ", function());

printf("%d  ", function());

printf("%d  ", function());

输出:0  3

很显然用静态变量记录了函数的执行状态,实际用的话这种方法问题太多了。我们把静态变量改为参数传递,再把协程用类封装一下。代码如下:

coroutine.h如下:

#ifndef COROUTINE_H_
#define COROUTINE_H_

#include "map"

 

typedef int (*FUNC)(void* pParam);
struct CrtParam
{
    int key;                                            //协程唯一识别标识
    FUNC func;                                     //处理函数
    void* pParam;                                //参数
    unsigned long yiledStart;              //挂起开始时间
    unsigned int yiledMillisecond;      //挂起时长

    CrtParam()
    {
        key = 0;
        func = NULL;
        pParam = NULL;
        yiledStart = 0;
        yiledMillisecond = 0;
    }
};
enum CoroutineState
{
     CS_FAILURE = -1,
     CS_SUCCESS,
     CS_YIELD,
     CS_YIELD_Timer,
};
typedef std::map "int, CrtParam*" CrtParamMap;
typedef CrtParamMap::iterator CrtParamMapItr;
class MyCoroutine
{
public:
     static void Init();
     static int Execute(CrtParam* pCrtParam);
     static CoroutineState Yiled();
     static CoroutineState YiledTimer(unsigned int yiledMillisecond);
     static void Resume(int key);
     static int CreateKey();
     static void HandleResumeTimer();

 

private:
     static CrtParamMap s_CrtParamMap;
     static int s_Key;
     static unsigned int s_yiledMillisecond;
};

 

#define YILED()  return MyCoroutine::Yiled();
#define YILEDTIME(yiledMillisecond)  return MyCoroutine::YiledTimer(yiledMillisecond);

void ResumeTimerFunc(void* pParam);

 

#endif

 

coroutine.cpp如下:

#include "stdafx.h"
#include "coroutine.h"
#include "time.h"
#include "process.h"
#include "windows.h"

 

CrtParamMap MyCoroutine::s_CrtParamMap;
int MyCoroutine::s_Key = 0;
unsigned int MyCoroutine::s_yiledMillisecond = 0;

void MyCoroutine::Init()
{
     _beginthread(&ResumeTimerFunc, 0, NULL);
}

int MyCoroutine::Execute(CrtParam* pCrtParam)
{
     int result = CS_FAILURE;
     if(NULL != pCrtParam && NULL != pCrtParam->func)
     {
          result = pCrtParam->func(pCrtParam->pParam);
          if (CS_SUCCESS == result || CS_FAILURE == result)
          {
               CrtParamMapItr ite = s_CrtParamMap.find(pCrtParam->key);
               if (ite != s_CrtParamMap.end())
               {
                    s_CrtParamMap.erase(ite);
               }
          }
          else 
          {
               pCrtParam->key = CreateKey();
               if(CS_YIELD_Timer == result)
               {
                    pCrtParam->yiledStart = GetTickCount();
                    pCrtParam->yiledMillisecond = s_yiledMillisecond;
               }
               CrtParamMapItr ite = s_CrtParamMap.find(pCrtParam->key);
               if (ite == s_CrtParamMap.end())
               {
                    s_CrtParamMap[pCrtParam->key] = pCrtParam;
               }
          }

     }
     return result;
}

CoroutineState MyCoroutine::Yiled()
{
     return CS_YIELD;
}
CoroutineState MyCoroutine::YiledTimer(unsigned int yiledMillisecond)
{
     s_yiledMillisecond = yiledMillisecond;
     return CS_YIELD_Timer;
}

void MyCoroutine::Resume(int key)
{
     CrtParamMapItr ite = s_CrtParamMap.find(key);
     if (ite != s_CrtParamMap.end())
     {
          Execute(ite->second);
     }
}

int MyCoroutine::CreateKey()
{
     return MyCoroutine::s_Key++;
}

void MyCoroutine::HandleResumeTimer()
{
     CrtParamMap crtParamMapTemp = s_CrtParamMap;
     for (CrtParamMapItr ite = crtParamMapTemp.begin(); ite != crtParamMapTemp.end(); ++ite)
     {
          if (ite->second->yiledStart > 0 && ite->second->yiledMillisecond > 0)
          {
               if (GetTickCount() >= ite->second->yiledStart + ite->second->yiledMillisecond)
               {
                    ite->second->yiledStart = 0;
                    ite->second->yiledMillisecond = 0;
                    Execute(ite->second); 
               }
          }
     }
}

void ResumeTimerFunc(void* pParam)
{
     while(true)
     {
          MyCoroutine::HandleResumeTimer();
          Sleep(50);
     }
}

 

看一下调用吧,先看不带时间的挂起YILED()。

struct Func1Param
{
     int index;
     int count;

     Func1Param()
     {
          index = 0;
          count = 10;
     }
};
int func1(void* pParam)
{
     Func1Param* pFunc1Param = (Func1Param*)pParam;
     if (NULL == pFunc1Param)
     {
          return CS_FAILURE;
     }

     while(pFunc1Param->index < pFunc1Param->count)
     {
          printf("%d  ", pFunc1Param->index);
          ++pFunc1Param->index;

          if (pFunc1Param->index == pFunc1Param->count / 2)
         
               YILED();
               //YILEDTIME(2000);
          }
     }

     return CS_SUCCESS;
}

 

int _tmain(int argc, _TCHAR* argv[])

{

     MyCoroutine::Init();

     CrtParam crtParam1;
     crtParam1.func = func1;
     Func1Param func1Param1;
     crtParam1.pParam = (void*)(&func1Param1);

 

    CrtParam crtParam2;
     crtParam2.func = func1;
     Func1Param func1Param2;
     func1Param2.count = 20;
     crtParam2.pParam = (void*)(&func1Param2);

 

     printf("fun1 Param1\n");
     MyCoroutine::Execute(&crtParam1);
     printf("\nfun1 Param2\n");
     MyCoroutine::Execute(&crtParam2);
     printf("\nfunc1 Param1 Resume\n");
     MyCoroutine::Resume(crtParam1.key);
     printf("\nfunc1 Param2 Resume\n");
     MyCoroutine::Resume(crtParam2.key);

 

     getchar();
     return 0;

}

 输出:

fun1 Param1

1   3  4

fun1 Param2

1   3      9

func1 Param1 Resume

    9

func1 Param2 Resume

10  11  12  13  14  15  16  17  18  19

 

带时间的挂起YILEDTIME():

 YILED();
 //YILEDTIME(2000);

修改为:

//YILED();
 YILEDTIME(2000);

main函数里,调用改为(不需要Resume):

printf("fun1 Param1\n");
 MyCoroutine::Execute(&crtParam1);
 printf("\nfun1 Param2\n");
 MyCoroutine::Execute(&crtParam2);

 输出:

fun1 Param1

1   3  4

fun1 Param2

1   3      

过2秒再输出:5      10  11  12  13  14  15  16  17  18  19

 

协程适合干一些轻量级的事,和一些限时等待。比如客户端向服务器发送数据,一定时间内要获取服务器的处理结果。

send();

YILEDTIME(1000);

int result = GetSeciveResult();

耗时和需要一直等待的处理还是要用多线程。

 

要想在处理函数里挂起多次,MyCoroutine::Execute的else分支需要处理一下,不然s_CrtParamMap会越来越大。


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有