示例#1
0
    void BackgroundJobProcessor::RemoveManager(JobManager *const manager)
    {
        Assert(manager);

        ParallelThreadData *threadDataProcessingCurrentJob = nullptr;        
        {
            AutoCriticalSection lock(&criticalSection);
            // Managers must remove themselves. Hence, Close does not remove managers. So, not asserting on !IsClosed().

            managers.Unlink(manager);
            if(manager->numJobsAddedToProcessor == 0)
            {
                Assert(!GetCurrentJobOfManager(manager));
                return;
            }

            // Remove this manager's jobs from the queue
            Job *firstJob = 0;
            for(Job *job = jobs.Head(); job; job = job->Next())
            {
                if(job->Manager() == manager)
                {
                    if(!firstJob)
                        firstJob = job;
                }
                else if(firstJob)
                {
                    jobs.UnlinkSubsequence(firstJob, job->Previous());
                    for(Job *removedJob = firstJob; removedJob;)
                    {
                        Job *const next = removedJob->Next();
                        Assert(!removedJob->IsCritical());
                        Assert(numJobs != 0);
                        --numJobs;
                        JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards
                        Assert(manager->numJobsAddedToProcessor != 0);
                        --manager->numJobsAddedToProcessor;
                        if(manager->isWaitable)
                        {
                            WaitableJobManager *const waitableManager = static_cast<WaitableJobManager *>(manager);
                            if(waitableManager->jobBeingWaitedUpon == removedJob)
                            {
                                waitableManager->jobBeingWaitedUponProcessed.Set();
                                waitableManager->jobBeingWaitedUpon = 0;
                            }
                        }
                        removedJob = next;
                    }
                    firstJob = 0;
                }
            }
            if(firstJob)
            {
                jobs.UnlinkSubsequenceFromEnd(firstJob);
                for(Job *removedJob = firstJob; removedJob;)
                {
                    Job *const next = removedJob->Next();
                    Assert(!removedJob->IsCritical());
                    Assert(numJobs != 0);
                    --numJobs;
                    JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards
                    Assert(manager->numJobsAddedToProcessor != 0);
                    --manager->numJobsAddedToProcessor;
                    if(manager->isWaitable)
                    {
                        WaitableJobManager *const waitableManager = static_cast<WaitableJobManager *>(manager);
                        if(waitableManager->jobBeingWaitedUpon == removedJob)
                        {
                            waitableManager->jobBeingWaitedUponProcessed.Set();
                            waitableManager->jobBeingWaitedUpon = 0;
                        }
                    }
                    removedJob = next;
                }
            }

            if(manager->numJobsAddedToProcessor == 0)
            {
                LastJobProcessed(manager);
                return;
            }

            Assert(manager->numJobsAddedToProcessor >= 1);
            Assert(manager->isWaitable);
            Assert(GetCurrentJobOfManager(manager));

        }

        //Wait for all the on going jobs to complete.
        criticalSection.Enter();
        while (true)
        {
            Job *job = GetCurrentJobOfManager(manager);
            if (!job)
            {
                break;
            }

            WaitableJobManager * const waitableManager = static_cast<WaitableJobManager *>(manager);
            Assert(!waitableManager->jobBeingWaitedUpon);

            waitableManager->jobBeingWaitedUpon = job;
            waitableManager->jobBeingWaitedUponProcessed.Reset();

            threadDataProcessingCurrentJob = GetThreadDataFromCurrentJob(waitableManager->jobBeingWaitedUpon);
            criticalSection.Leave();

            WaitWithThread(threadDataProcessingCurrentJob, waitableManager->jobBeingWaitedUponProcessed);

            criticalSection.Enter();
            waitableManager->jobBeingWaitedUpon = 0;
        }
        criticalSection.Leave();
    }