对程序驱动机制的一些理解

一个程序处于一个死循环当中,在循环中执行功能:
int main()
{
   bool bQuit = false;
   while(!bQuit)
   {
      char c = getchar();
      if(c == 'q')
         break;
      else if( c == ...)
      {
         ...
      }
   }
   
   return 0;
}

上述给程序分配任务是通过用户输入字符完成的,在简单程序中是可以的,只要任务种类不是很多;但是如果某一天,系统功能不断扩充,功能不断增加,256个字符不足以表示所有的任务种类;这时你可以想到用int类型,足以代表相当种类的数量,也是可行方法;后来,某一天,你发现,给程序分配任务不仅仅通过人的输入,在程序执行的某一步也想要向程序下达下一步进行的任务,此时你想到能不能通过一个队列,把程序要执行的功能存储起来,每次循环中从队列中取任务来响应,任务的表示可以通过一个结构体或类来表示,那么任务的表示更加丰富,更易于扩展;所以出现了下面的模型:

int main()
{
   while(1)
   {
       Event event = GetPendingEventFromQueue();
       if (event.Quit = true)
          break;
          
       ProcessEvent(event);
   }
}

void Process(Event event)
{
   ...
   PostEventToQueue(newevent);
   ...
}

对列中的event可以设定优先级,实现实时处理的目的;从队列中取event后,可以将该event中队列中删除,也可以不删除;上面就是基于任务驱动的程序了;该模型中的血液中具有状态机的功能;其实程序执行流程也是从一个状态到另外一个状态的变换过程;再后来的某一天,你需要并行处理某些任务,需要启动新的线程来执行另外的功能,怎么办?只要有了队列,一切问题都可以解决,worker线程函数中只要这样:

unsigned int TreadFunction(void* arg)
{
   while(1)
   {
       Event event = GetEventFromThreadQueue();
       if(event.Quit == true)
          break;
          
        ProcessTreadEvent(event);
   }
}

void ProcessTreadEvent(Event event)
{
   ...
   //要与main线程通信,或协作完成某项任务
   PostEventToMainQueue(newevent);
   ...
}

在main线程中,如果要worker线程执行某项任务,只要PostEventToWorkerQueue(event)即可;
main线程,与worker线程都有自己的event队列,只要不断从自己的队列中取任务,执行任务;

从上面的模型中可以得到如下结论:
main线程与worker线程都是线程,线程都应该有自己的任务队列,线程公司处在一个死循环当中,
死循环中线程从自己队列中取任务,执行任务;这种任务驱动的模型可以大大简化问题;处理复杂问题
时更得心应手;

有些同学可能会有疑问,如果我再main线程中向worker线程中投递一个event,但是我想知道该event的
执行结果后,再决定我再main线程中的下一步工作,如何处理?这个也不是问题!
方法有很多,例如回调函数,或者Future模式;

Future模式简单字面理解就是将来的事情;一个可行的实现方法是;
Future* future = PostEventToWorkerQueue(event);
bool result = future->GetReuslt();
future->release();//多线程中,一般通过引用计数来解决对象生命期问题
if(result == true)
   ...
else
   ...

 
void PostEventToWorkerQueue(event)
{
    Future* future = new Future();
    future->Increase();
    event.SetFuture(future);
    
    ...
}

在Future内部可以包含一个事件(widnows中),当投递到worker线程的event处理完成后,
event可以激发Fucure内部的事件,使future->GetReuslt()内部会从阻塞的事件当中醒过来;

Future::GetResult()
{
   ::WaitForSingleObject(m_hEvent, INFINIT);
   reutrn m_bResult;
}

计算机程序都是相同的,在操作系统内部也有个任务队列,操作系统也是在死循环当中取任务,执行任务;
所以说,把基础打好很重要,这样理解问题很透彻,深刻;

widnows程序中也有个队列,叫消息队列,在main线程中有个如下的消息循环:
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    {
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
从消息队列中取消息,然后向窗口函数派发消息;
在windows的线程中也可以有个消息队列,只需在线程函数开始出呼叫PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);这样该线程便有了个消息队列,该队列可以容纳的最大消失数目是10000;
然后线程函数中可以通过GetMessage或PeekMessage从队列中取出消息;

有了上面的了解,那么自然可以想到实践中windows中UI线程如何与workder线程通信,
通过PostMessage或PostThreadMesage;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值