一个程序处于一个死循环当中,在循环中执行功能:
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;
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;