65.9K
CodeProject 正在变化。 阅读更多。
Home

工作队列

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (41投票s)

2003年2月2日

3分钟阅读

viewsIcon

277343

downloadIcon

7184

简单而优雅的线程池。

Sample Image - Work_Queue.gif

引言

在需要以最快速度响应和处理不同任务,并且这些任务可以并发处理的实时系统中,需要一定数量的线程等待、准备并能够执行手头的任务。这可以通过针对每个特定作业的特定结构方案,或者通过称为线程池的通用方法来实现。工作队列是一种简单而优雅的线程池,它在创建时创建所需数量的线程,并管理一个包含不同工作项的队列,这些工作项实现了特定的任务,其中每个工作项轮流获得一个线程来工作和处理它。

如何使用

首先,需要定义一种新的工作项类型,其格式可以由工作队列处理。为此,您需要实现一个工作项类,该类继承自基类工作项WorkItemBaseWorkItemBase有两个需要实现的抽象函数。第一个DoWork是当工作项在队列中轮到它时将由空闲线程执行的方法。第二个Abort是在队列在工作项轮到它之前被销毁时调用的。具体的工作项应该按如下方式实现。

class SpecificWorkItem : public WorkItemBase
{
    void   DoWork(void* pThreadContext);
    void   Abort();

 //memeber variables needed here
};

void   SpecificWorkItem::DoWork(void* pThreadContext)
{
  //Notify Start
  //proccessing done here
  //Notify Finish
  //free all that was occupied
}

void   SpecificWorkItem::Abort()
{
  //Notify aborted
  //free all that was occupied
}

请注意,不同类型的工作项可以在同一个工作队列中处理。在工作队列中,首先需要调用Create函数,其中第一个参数是线程数,第二个参数是指向线程数据结构体的指针数组。这些结构可以用作每个线程的工作表面。这用于减少在DoWork函数中声明的局部变量和为每个正在处理的项进行动态分配,以便优化处理。

CWorkQueue WorkQueue;
WorkQueue.Create(5);

如您在代码中看到的,可以忽略第二个参数,其默认值为NULL。接下来,要将工作项插入到队列中,您需要使用新创建的工作项调用InsertWorkItem。此函数可以异步调用。

SpecificWorkItem* pWorkItem = new SpecificWorkItem()
// prepare the work item for the task
m_WorkQueue.InsertWorkItem(pWorkItem);

在使用工作队列后,您必须调用Destroy函数。此函数将等待,直到所有线程完成处理已经从队列中取出的工作项,然后调用每个正在等待队列中处理的工作项Abort函数。

m_WorkQueue.Destroy();

实现

工作队列是使用 STL queue工作项实现的,通过互斥锁、初始化为零的信号量、一个终止事件和一组为运行特定函数而创建的线程来保证在异步系统中工作。此函数正在等待两个异步对象。首先是终止事件,如果设置了该事件,线程将从函数返回。其次是信号量,如果释放了该信号量,线程将从队列中提取下一个项并调用其DoWork函数。在插入函数中,在插入工作项后释放信号量(增加1),允许其中一个线程附加到工作函数。当依次调用Destroy函数时,设置终止事件,并且函数等待所有线程终止。对于队列中剩下的每个工作项,它会调用它们的Abort函数。

演示项目

演示项目是我包含的,仅仅是为了说明工作队列的执行方式。您需要做的就是

  1. 确定您想要的线程数
  2. 单击创建按钮以创建工作队列
  3. 通过单击插入项按钮将工作项插入队列
  4. 销毁工作队列,单击销毁按钮。

享受。

感谢 Hans Dietrich 提供的 XlistCtrl

© . All rights reserved.