///Main loop for managing threads and tasks. void ODManager::Start() { ODTask* task; ODTaskThread* thread; bool tasksInArray; //wxLog calls not threadsafe. are printfs? thread-messy for sure, but safe? printf("ODManager thread strating \n"); //TODO: Figure out why this has no effect at all. //wxThread::This()->SetPriority(30); mTerminateMutex.Lock(); while(!mTerminate) { mTerminateMutex.Unlock(); //we should look at our WaveTrack queues to see if we can process a new task to the running queue. UpdateQueues(); //start some threads if necessary mTasksMutex.Lock(); tasksInArray = mTasks.size()>0; mTasksMutex.Unlock(); mCurrentThreadsMutex.Lock(); while( tasksInArray&& mCurrentThreads < mMaxThreads) { mCurrentThreads++; mCurrentThreadsMutex.Unlock(); //remove the head mTasksMutex.Lock(); task = mTasks[0]; //the thread will add it back to the array if the job is not yet done at the end of the thread's run. mTasks.erase(mTasks.begin()); mTasksMutex.Unlock(); //detach a new thread. thread = new ODTaskThread(task); // thread->SetPriority(10);//default is 50. thread->Create(); thread->Run(); mTasksMutex.Lock(); tasksInArray = mTasks.size()>0; mTasksMutex.Unlock(); mCurrentThreadsMutex.Lock(); } mCurrentThreadsMutex.Unlock(); wxThread::Sleep(200); //wxSleep can't be called from non-main thread. // ::wxMilliSleep(250); mTerminateMutex.Lock(); //if there is some ODTask running, then there will be something in the queue. If so then redraw to show progress mQueuesMutex.Lock(); mNeedsDraw += mQueues.size()>0?1:0; mQueuesMutex.Unlock(); // // //TODO:this is a little excessive, in the future only redraw some, and if possible only the Tracks on the trackpanel.. if(mNeedsDraw > 18) { mNeedsDraw=0; wxCommandEvent event( wxEVT_ODTASK_UPDATE ); AudacityProject::AllProjectsDeleteLock(); AudacityProject* proj = GetActiveProject(); if(proj) proj->AddPendingEvent( event ); AudacityProject::AllProjectsDeleteUnlock(); } } mTerminateMutex.Unlock(); //wxLogDebug Not thread safe. //printf("ODManager thread terminating\n"); }
///Do a modular part of the task. For example, if the task is to load the entire file, load one BlockFile. ///Relies on DoSomeInternal(), which is the subclasses must implement. ///@param amountWork the percent amount of the total job to do. 1.0 represents the entire job. the default of 0.0 /// will do the smallest unit of work possible void ODTask::DoSome(float amountWork) { mBlockUntilTerminateMutex.Lock(); printf("%s %i subtask starting on new thread with priority\n", GetTaskName(),GetTaskNumber()); mDoingTask=mTaskStarted=true; float workUntil = amountWork+PercentComplete(); if(workUntil<PercentComplete()) workUntil = PercentComplete(); //check periodically to see if we should exit. mTerminateMutex.Lock(); if(mTerminate) { mBlockUntilTerminateMutex.Unlock(); mTerminateMutex.Unlock(); return; } mTerminateMutex.Unlock(); Update(); //Do Some of the task. mTerminateMutex.Lock(); while(PercentComplete() < workUntil && PercentComplete() < 1.0 && !mTerminate) { wxThread::This()->Yield(); //release within the loop so we can cut the number of iterations short mTerminateMutex.Unlock(); //TODO: check to see if ondemand has been called if(false) ODUpdate(); DoSomeInternal(); //But add the mutex lock back before we check the value again. mTerminateMutex.Lock(); } mTerminateMutex.Unlock(); mDoingTask=false; mTerminateMutex.Lock(); //if it is not done, put it back onto the ODManager queue. if(!IsComplete() && !mTerminate) { ODManager::Instance()->AddTask(this); printf("%s %i is %f done\n", GetTaskName(),GetTaskNumber(),PercentComplete()); } else { wxCommandEvent event( wxEVT_ODTASK_COMPLETE ); AudacityProject::AllProjectsDeleteLock(); AudacityProject* proj = GetActiveProject(); if(proj) proj->AddPendingEvent( event ); AudacityProject::AllProjectsDeleteUnlock(); printf("%s %i complete\n", GetTaskName(),GetTaskNumber()); } mTerminateMutex.Unlock(); mBlockUntilTerminateMutex.Unlock(); }