Fixed a bug in AbstractTool class that could cause a severe slow-down on process creation, especially with a large number of threads: The same mutex was used in the constructor and the startProcess() function, which is unnecessary anyway. But even worse, there was a sleep() call in the startProcess() function that could *block* the mutex for a very long time! So if the "main" thread tried to create a new object while one of the "worker" threads was sleeping inside startProcess(), this blocked the whole "main" thread. D'oh!

This commit is contained in:
LoRd_MuldeR 2014-12-05 22:39:31 +01:00
parent 8211b417d6
commit 67429fbada
5 changed files with 32 additions and 36 deletions

View File

@ -30,4 +30,7 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal EndGlobal

View File

@ -27,6 +27,8 @@ a:visited { color: #0000EE; }
<li>Updated Vorbis decoder to OggDec v1.10.1 (2014-06-25), using libVorbis v1.3.4 <li>Updated Vorbis decoder to OggDec v1.10.1 (2014-06-25), using libVorbis v1.3.4
<li>Updated GnuPG to v1.4.18 (2014-06-30), compiled with GCC 4.9.1 <li>Updated GnuPG to v1.4.18 (2014-06-30), compiled with GCC 4.9.1
<li>Fixed potential crash in Cue Sheet importer (occurred when *all* input files were missing) <li>Fixed potential crash in Cue Sheet importer (occurred when *all* input files were missing)
<li>Fixed a severe performance bottleneck, especially with a large number of parallel instances
<li>The limit for the maximum number of parallel instances has been increased to 32
<li>Experimental support for Windows 10 Technical Preview <li>Experimental support for Windows 10 Technical Preview
</ul><br> </ul><br>

View File

@ -34,8 +34,8 @@
#define VER_LAMEXP_MINOR_HI 1 #define VER_LAMEXP_MINOR_HI 1
#define VER_LAMEXP_MINOR_LO 1 #define VER_LAMEXP_MINOR_LO 1
#define VER_LAMEXP_TYPE Beta #define VER_LAMEXP_TYPE Beta
#define VER_LAMEXP_PATCH 4 #define VER_LAMEXP_PATCH 5
#define VER_LAMEXP_BUILD 1615 #define VER_LAMEXP_BUILD 1616
#define VER_LAMEXP_CONFG 1558 #define VER_LAMEXP_CONFG 1558
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -39,34 +39,33 @@
#include <QDir> #include <QDir>
/* /*
* Static vars * Job Object
*/ */
quint64 AbstractTool::s_lastLaunchTime = 0ui64; QScopedPointer<JobObject> AbstractTool::s_jobObject;
QMutex AbstractTool::s_mutex_startProcess; QMutex AbstractTool::s_jobObjMtx;
JobObject *AbstractTool::s_jobObject = NULL;
unsigned int AbstractTool::s_jobObjRefCount = 0U; /*
* Process Timer
*/
quint64 AbstractTool::s_startProcessTimer = 0ui64;
QMutex AbstractTool::s_startProcessMutex;
/* /*
* Const * Const
*/ */
static const unsigned int START_DELAY = 333; //in milliseconds static const unsigned int START_DELAY = 50U; //in milliseconds
static const quint64 START_DELAY_NANO = START_DELAY * 1000 * 10; //in 100-nanosecond intervals static const quint64 START_DELAY_NANO = quint64(START_DELAY) * 10000ui64; //in 100-nanosecond intervals
/* /*
* Constructor * Constructor
*/ */
AbstractTool::AbstractTool(void) AbstractTool::AbstractTool(void)
{ {
QMutexLocker lock(&s_mutex_startProcess); QMutexLocker lock(&s_jobObjMtx);
if(s_jobObjRefCount < 1U) if(s_jobObject.isNull())
{ {
s_jobObject = new JobObject(); s_jobObject.reset(new JobObject());
s_jobObjRefCount = 1U;
}
else
{
s_jobObjRefCount++;
} }
m_firstLaunch = true; m_firstLaunch = true;
@ -77,16 +76,6 @@ AbstractTool::AbstractTool(void)
*/ */
AbstractTool::~AbstractTool(void) AbstractTool::~AbstractTool(void)
{ {
QMutexLocker lock(&s_mutex_startProcess);
if(s_jobObjRefCount >= 1U)
{
s_jobObjRefCount--;
if(s_jobObjRefCount < 1U)
{
MUTILS_DELETE(s_jobObject);
}
}
} }
/* /*
@ -94,11 +83,13 @@ AbstractTool::~AbstractTool(void)
*/ */
bool AbstractTool::startProcess(QProcess &process, const QString &program, const QStringList &args) bool AbstractTool::startProcess(QProcess &process, const QString &program, const QStringList &args)
{ {
QMutexLocker lock(&s_mutex_startProcess); QMutexLocker lock(&s_startProcessMutex);
if(MUtils::OS::current_file_time() <= s_lastLaunchTime) while(MUtils::OS::current_file_time() <= s_startProcessTimer)
{ {
lock.unlock();
MUtils::OS::sleep_ms(START_DELAY); MUtils::OS::sleep_ms(START_DELAY);
lock.relock();
} }
emit messageLogged(commandline2string(program, args) + "\n"); emit messageLogged(commandline2string(program, args) + "\n");
@ -117,7 +108,6 @@ bool AbstractTool::startProcess(QProcess &process, const QString &program, const
} }
MUtils::OS::change_process_priority(&process, -1); MUtils::OS::change_process_priority(&process, -1);
lock.unlock();
if(m_firstLaunch) if(m_firstLaunch)
{ {
@ -125,7 +115,7 @@ bool AbstractTool::startProcess(QProcess &process, const QString &program, const
m_firstLaunch = false; m_firstLaunch = false;
} }
s_lastLaunchTime = MUtils::OS::current_file_time() + START_DELAY_NANO; s_startProcessTimer = MUtils::OS::current_file_time() + START_DELAY_NANO;
return true; return true;
} }
@ -136,7 +126,7 @@ bool AbstractTool::startProcess(QProcess &process, const QString &program, const
process.kill(); process.kill();
process.waitForFinished(-1); process.waitForFinished(-1);
s_lastLaunchTime = MUtils::OS::current_file_time() + START_DELAY_NANO; s_startProcessTimer = MUtils::OS::current_file_time() + START_DELAY_NANO;
return false; return false;
} }

View File

@ -47,10 +47,11 @@ protected:
static const int m_processTimeoutInterval = 600000; static const int m_processTimeoutInterval = 600000;
private: private:
static quint64 s_lastLaunchTime; static quint64 s_startProcessTimer;
static QMutex s_mutex_startProcess; static QMutex s_startProcessMutex;
static unsigned int s_jobObjRefCount;
static JobObject *s_jobObject; static QScopedPointer<JobObject> s_jobObject;
static QMutex s_jobObjMtx;
bool m_firstLaunch; bool m_firstLaunch;
}; };