AnvilStats: Fixed thread start race condition.
The whole program would sometimes fail to process anything because the threads were waited-for before they were started.
This commit is contained in:
parent
af47b5ece2
commit
cde195c156
@ -28,6 +28,7 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
|
|||||||
m_Callback(a_Callback),
|
m_Callback(a_Callback),
|
||||||
m_ParentProcessor(a_ParentProcessor)
|
m_ParentProcessor(a_ParentProcessor)
|
||||||
{
|
{
|
||||||
|
LOG("Created a new thread: %p", this);
|
||||||
super::Start();
|
super::Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,11 +36,20 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProcessor::cThread::WaitForStart(void)
|
||||||
|
{
|
||||||
|
m_HasStarted.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProcessor::cThread::Execute(void)
|
void cProcessor::cThread::Execute(void)
|
||||||
{
|
{
|
||||||
LOG("Started a new thread: %d", cIsThread::GetCurrentID());
|
LOG("Started a new thread: %p, ID %d", this, cIsThread::GetCurrentID());
|
||||||
|
|
||||||
m_ParentProcessor.m_ThreadsHaveStarted.Set();
|
m_HasStarted.Set();
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -52,7 +62,7 @@ void cProcessor::cThread::Execute(void)
|
|||||||
ProcessFile(FileName);
|
ProcessFile(FileName);
|
||||||
} // for-ever
|
} // for-ever
|
||||||
|
|
||||||
LOG("Thread %d terminated", cIsThread::GetCurrentID());
|
LOG("Thread %p (ID %d) terminated", this, cIsThread::GetCurrentID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -522,20 +532,18 @@ void cProcessor::ProcessWorld(const AString & a_WorldFolder, cCallbackFactory &
|
|||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
//*/
|
//*/
|
||||||
|
|
||||||
|
// Start all the threads:
|
||||||
for (int i = 0; i < NumThreads; i++)
|
for (int i = 0; i < NumThreads; i++)
|
||||||
{
|
{
|
||||||
cCallback * Callback = a_CallbackFactory.GetNewCallback();
|
cCallback * Callback = a_CallbackFactory.GetNewCallback();
|
||||||
m_Threads.push_back(new cThread(*Callback, *this));
|
m_Threads.push_back(new cThread(*Callback, *this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the first thread to start processing:
|
// Wait for all threads to finish:
|
||||||
m_ThreadsHaveStarted.Wait();
|
|
||||||
|
|
||||||
// Wait for all threads to finish
|
|
||||||
// simply by calling each thread's destructor sequentially
|
|
||||||
LOG("Waiting for threads to finish");
|
LOG("Waiting for threads to finish");
|
||||||
for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
|
for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
|
(*itr)->WaitForStart();
|
||||||
delete *itr;
|
delete *itr;
|
||||||
} // for itr - m_Threads[]
|
} // for itr - m_Threads[]
|
||||||
LOG("Processor finished");
|
LOG("Processor finished");
|
||||||
|
@ -30,6 +30,7 @@ class cProcessor
|
|||||||
|
|
||||||
cCallback & m_Callback;
|
cCallback & m_Callback;
|
||||||
cProcessor & m_ParentProcessor;
|
cProcessor & m_ParentProcessor;
|
||||||
|
cEvent m_HasStarted;
|
||||||
|
|
||||||
// cIsThread override:
|
// cIsThread override:
|
||||||
virtual void Execute(void) override;
|
virtual void Execute(void) override;
|
||||||
@ -48,6 +49,9 @@ class cProcessor
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
cThread(cCallback & a_Callback, cProcessor & a_ParentProcessor);
|
cThread(cCallback & a_Callback, cProcessor & a_ParentProcessor);
|
||||||
|
|
||||||
|
/** Waits until the thread starts processing the callback code. */
|
||||||
|
void WaitForStart(void);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
typedef std::vector<cThread *> cThreads;
|
typedef std::vector<cThread *> cThreads;
|
||||||
@ -65,10 +69,12 @@ protected:
|
|||||||
AStringList m_FileQueue;
|
AStringList m_FileQueue;
|
||||||
|
|
||||||
cThreads m_Threads;
|
cThreads m_Threads;
|
||||||
cEvent m_ThreadsHaveStarted; // This is signalled by each thread to notify the parent thread that it can start waiting for those threads
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Populates m_FileQueue with Anvil files from the specified folder. */
|
||||||
void PopulateFileQueue(const AString & a_WorldFolder);
|
void PopulateFileQueue(const AString & a_WorldFolder);
|
||||||
|
|
||||||
|
/** Returns one filename from m_FileQueue, and removes the name from the queue. */
|
||||||
AString GetOneFileName(void);
|
AString GetOneFileName(void);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user