如何用多任务处理 求助 c++
2014-12-05 · 知道合伙人数码行家
huanglenzhi
知道合伙人数码行家
向TA提问 私信TA
知道合伙人数码行家
采纳数:117538
获赞数:517179
长期从事计算机组装,维护,网络组建及管理。对计算机硬件、操作系统安装、典型网络设备具有详细认知。
向TA提问 私信TA
关注
展开全部
在某些系统中,需要你自己来构建自己的异步多任务处理框架。通过这种多任务处理,可以自己实现事件驱动编程模型的一个小部分。当然,event driven is good for computer but not for human beings,人要是事件驱动,要么他是消防队员,要么他很失败,呵呵。另外,当存在典型的情况 “等待数据->处理数据->等待数据”循环时,用异步处理能够大大增加系统的性能,尤其是出现数据和处理互相依赖的关系时。如:任务A的输出数据是任务B的输入,而B的输出又是C的输入,而且B和C在进行数据处理之前需要花费大量时间来做初始化,线性处理显然会有性能瓶颈。采用异步处理能改善这种情况,当有多个处理器时性能将得到极大的提高。
本文描述的异步多任务是通过同一进程内的调度器来调度该进程内多个异步任务,这些异步任务的真正执行是通过工作线程来完成。其模型为:各异步的任务发送请求后阻塞;当其请求的任务完成后,调度器唤醒该任务并执行相应的处理(也许会再次发送一个请求)。这时一个典型的生产者/消费者的问题:在调度器中,生产者是任务,而调度器是消费者。一旦任务的请求完成,调度器则执行该任务。
处理流程
由于scheduler是在一个进程中,因此需要先将scheduler安装到进程中,然后将各异步任务添加到scheduler,之后,各异步任务发送第一个请求等待完成。最后启动scheduler,处理各个已经完成请求。如下图所示:
任务
每个任务都应当继承自同一个基类以使得调度器可以以相同的方式处理他们。每个派生的任务都应当包含(至少)一个异步操作(或所属对象),该操作可以执行1~n次。每次异步操作完成之后,其Run()函数将被调用以进行后续处理。因此,任务至少应当具有一个状态成员用于指示该任务所处的状态。当任务处理完毕之后,任务可以把自己从调度队列中移出。由于添加任务到调度队列的操作应当由调度器而不是任务本身来做,因此,不需要Add()操作。因此,任务类应当象这样:
其中:
StartWorker()、Dequeue()都是由TaskBase来实现的:
int TaskBase::Dequeue()
{
Scheduler* sched = SchedulerInstance::GetInstance();
int ret = ErrNone;
m_Mutex->Lock();
if (sched && m_Status != TaskPending)
sched->Remove(this);
else
ret = ErrTaskBusy;
m_Mutex->Unlock();
return ret;
}
int TaskBase::StartWorker()
{
Scheduler* sched = SchedulerInstance::GetInstance();
int ret = ErrNone;
m_Mutex->Lock();
if (sched && (m_Status != TaskPending || m_Status != NotAvailable))
{
m_Worker->RunThread(this);
}
else
ret = ErrTaskBusy;
m_Mutex->Unlock();
return ret;
}
void TaskBase::CancelWorker()
{
Scheduler* sched = SchedulerInstance::GetInstance();
m_Mutex->Lock();
if (sched && m_Status == TaskPending)
{
m_Worker->Cancel();
m_Status = TaskCancelled;
}
m_Mutex->Unlock();
}
由于使用了工作线程来进行真正的异步操作,因此,应当有一个静态函数来作为线程的入口函数。
其实现为:
void WorkerThread::ThreadFunction(void* aData)
{
TaskBase* task = static_cast<TaskBase*>(aData);
if (task)
task->IssueRequest();
// Notify the Scheduler
Scheduler* sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}
由于工作线程的实现与平台相关,因此此处列出Linux平台的典型实现:
void LinuxThread::RunThread(void* aData)
{
pthread_create(&m_TID, NULL, WorkerThread::ThreadFunction, aData);
Scheduler* sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}
void LinuxThread::Cancel()
{
pthread_cancel(m_TID);
Scheduler* sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}
本文描述的异步多任务是通过同一进程内的调度器来调度该进程内多个异步任务,这些异步任务的真正执行是通过工作线程来完成。其模型为:各异步的任务发送请求后阻塞;当其请求的任务完成后,调度器唤醒该任务并执行相应的处理(也许会再次发送一个请求)。这时一个典型的生产者/消费者的问题:在调度器中,生产者是任务,而调度器是消费者。一旦任务的请求完成,调度器则执行该任务。
处理流程
由于scheduler是在一个进程中,因此需要先将scheduler安装到进程中,然后将各异步任务添加到scheduler,之后,各异步任务发送第一个请求等待完成。最后启动scheduler,处理各个已经完成请求。如下图所示:
任务
每个任务都应当继承自同一个基类以使得调度器可以以相同的方式处理他们。每个派生的任务都应当包含(至少)一个异步操作(或所属对象),该操作可以执行1~n次。每次异步操作完成之后,其Run()函数将被调用以进行后续处理。因此,任务至少应当具有一个状态成员用于指示该任务所处的状态。当任务处理完毕之后,任务可以把自己从调度队列中移出。由于添加任务到调度队列的操作应当由调度器而不是任务本身来做,因此,不需要Add()操作。因此,任务类应当象这样:
其中:
StartWorker()、Dequeue()都是由TaskBase来实现的:
int TaskBase::Dequeue()
{
Scheduler* sched = SchedulerInstance::GetInstance();
int ret = ErrNone;
m_Mutex->Lock();
if (sched && m_Status != TaskPending)
sched->Remove(this);
else
ret = ErrTaskBusy;
m_Mutex->Unlock();
return ret;
}
int TaskBase::StartWorker()
{
Scheduler* sched = SchedulerInstance::GetInstance();
int ret = ErrNone;
m_Mutex->Lock();
if (sched && (m_Status != TaskPending || m_Status != NotAvailable))
{
m_Worker->RunThread(this);
}
else
ret = ErrTaskBusy;
m_Mutex->Unlock();
return ret;
}
void TaskBase::CancelWorker()
{
Scheduler* sched = SchedulerInstance::GetInstance();
m_Mutex->Lock();
if (sched && m_Status == TaskPending)
{
m_Worker->Cancel();
m_Status = TaskCancelled;
}
m_Mutex->Unlock();
}
由于使用了工作线程来进行真正的异步操作,因此,应当有一个静态函数来作为线程的入口函数。
其实现为:
void WorkerThread::ThreadFunction(void* aData)
{
TaskBase* task = static_cast<TaskBase*>(aData);
if (task)
task->IssueRequest();
// Notify the Scheduler
Scheduler* sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}
由于工作线程的实现与平台相关,因此此处列出Linux平台的典型实现:
void LinuxThread::RunThread(void* aData)
{
pthread_create(&m_TID, NULL, WorkerThread::ThreadFunction, aData);
Scheduler* sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}
void LinuxThread::Cancel()
{
pthread_cancel(m_TID);
Scheduler* sched = SchedulerInstance::GetInstance();
if (sched)
sched->Notify();
}
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询