Fix: In order to ensure the "correct" ordering, *all* threads need to wait for the previous threads to finish - not only the threads that will emit a file. If both, thread n and n+1, want to emit a file and thus n+1 has to wait for n, we additionally must allow thread n+2 to terminate before n and n+1, even if n+2 does *not* emit a file. That's because as soon as n+2 finishes, it unblocks all threads x with x < n+2, which includes n and n+1. If that happens and n+1 is still waiting for n, we effectively allow n+1 to emit its file *before* n. By blocking all threads x with x > n+1 until n+1 has finished (regardless of whether they want to emit a file or not) this problem is resolved. As long as we assume that most threads actually *do* emit a file, this commit shouldn't hurt the performance.
This commit is contained in:
parent
68d2a28c7b
commit
193488e26f
@ -43,7 +43,7 @@
|
||||
WorkingBanner::WorkingBanner(QWidget *parent)
|
||||
:
|
||||
QDialog(parent, Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint),
|
||||
m_progressMax(0), m_progressVal(0), m_metrics(NULL)
|
||||
m_progressMax(0), m_progressVal(0), m_progressInt(0), m_metrics(NULL)
|
||||
{
|
||||
//Init the dialog, from the .ui file
|
||||
setupUi(this);
|
||||
@ -226,25 +226,41 @@ void WorkingBanner::setText(const QString &text)
|
||||
}
|
||||
labelStatus->setText(choppedText);
|
||||
}
|
||||
/*
|
||||
if(this->isVisible())
|
||||
{
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
labelStatus->repaint();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void WorkingBanner::setProgressMax(unsigned int max)
|
||||
{
|
||||
m_progressMax = max;
|
||||
updateProgress();
|
||||
}
|
||||
|
||||
void WorkingBanner::setProgressVal(unsigned int val)
|
||||
{
|
||||
m_progressVal = val;
|
||||
updateProgress();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void WorkingBanner::updateProgress(void)
|
||||
{
|
||||
if(m_progressMax > 0)
|
||||
{
|
||||
int progress = qRound(qBound(0.0, static_cast<double>(m_progressVal) / static_cast<double>(m_progressMax), 1.0) * 100.0);
|
||||
m_progress->setText(QString::number(progress));
|
||||
int newProgress = qRound(qBound(0.0, static_cast<double>(m_progressVal) / static_cast<double>(m_progressMax), 1.0) * 100.0);
|
||||
if(m_progressInt != newProgress)
|
||||
{
|
||||
m_progressInt = newProgress;
|
||||
m_progress->setText(QString::number(m_progressInt));
|
||||
if(this->isVisible())
|
||||
{
|
||||
labelStatus->repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
private:
|
||||
QMovie *m_working;
|
||||
bool m_canClose;
|
||||
void updateProgress(void);
|
||||
|
||||
public slots:
|
||||
void setText(const QString &text);
|
||||
@ -62,4 +63,5 @@ protected:
|
||||
QFontMetrics *m_metrics;
|
||||
unsigned int m_progressMax;
|
||||
unsigned int m_progressVal;
|
||||
unsigned int m_progressInt;
|
||||
};
|
||||
|
@ -133,14 +133,7 @@ void FileAnalyzer::run()
|
||||
QThreadPool *pool = new QThreadPool();
|
||||
QThread::msleep(333);
|
||||
|
||||
if(QThread::idealThreadCount() > 1)
|
||||
{
|
||||
pool->setMaxThreadCount((QThread::idealThreadCount() * 3) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->setMaxThreadCount(2);
|
||||
}
|
||||
pool->setMaxThreadCount(qBound(2, ((QThread::idealThreadCount() * 3) / 2), 12));
|
||||
|
||||
while(!(m_inputFiles.isEmpty() || m_bAborted))
|
||||
{
|
||||
@ -156,10 +149,7 @@ void FileAnalyzer::run()
|
||||
|
||||
while(!pool->tryStart(task))
|
||||
{
|
||||
if(!AnalyzeTask::waitForOneThread(1250))
|
||||
{
|
||||
qWarning("FileAnalyzer: Timeout, retrying!");
|
||||
}
|
||||
AnalyzeTask::waitForOneThread();
|
||||
|
||||
if(m_abortFlag)
|
||||
{
|
||||
@ -175,7 +165,8 @@ void FileAnalyzer::run()
|
||||
MessageBeep(MB_ICONERROR);
|
||||
m_bAborted = true;
|
||||
}
|
||||
else
|
||||
|
||||
if(!m_bAborted)
|
||||
{
|
||||
if(int count = AnalyzeTask::getAdditionalFiles(m_inputFiles))
|
||||
{
|
||||
|
@ -56,7 +56,11 @@ unsigned int AnalyzeTask::s_filesDenied;
|
||||
unsigned int AnalyzeTask::s_filesDummyCDDA;
|
||||
unsigned int AnalyzeTask::s_filesCueSheet;
|
||||
QStringList AnalyzeTask::s_additionalFiles;
|
||||
QStringList AnalyzeTask::s_recentlyAdded;
|
||||
QSet<QString> AnalyzeTask::s_recentlyAdded;
|
||||
|
||||
/*constants*/
|
||||
const int WAITCOND_TIMEOUT = 2500;
|
||||
const int MAX_RETRIES = 60000 / WAITCOND_TIMEOUT;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
@ -126,6 +130,7 @@ void AnalyzeTask::run_ex(void)
|
||||
}
|
||||
if(fileType == fileTypeSkip)
|
||||
{
|
||||
waitForPreviousThreads();
|
||||
qWarning("File was recently added, skipping!");
|
||||
return;
|
||||
}
|
||||
@ -133,6 +138,8 @@ void AnalyzeTask::run_ex(void)
|
||||
{
|
||||
QWriteLocker lock(&s_lock);
|
||||
s_filesDenied++;
|
||||
lock.unlock();
|
||||
waitForPreviousThreads();
|
||||
qWarning("Cannot access file for reading, skipping!");
|
||||
return;
|
||||
}
|
||||
@ -140,10 +147,13 @@ void AnalyzeTask::run_ex(void)
|
||||
{
|
||||
QWriteLocker lock(&s_lock);
|
||||
s_filesDummyCDDA++;
|
||||
lock.unlock();
|
||||
waitForPreviousThreads();
|
||||
qWarning("Dummy CDDA file detected, skipping!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Handle files with *incomplete* meida info
|
||||
if(file.fileName().isEmpty() || file.formatContainerType().isEmpty() || file.formatAudioType().isEmpty())
|
||||
{
|
||||
QStringList fileList;
|
||||
@ -167,9 +177,8 @@ void AnalyzeTask::run_ex(void)
|
||||
{
|
||||
QWriteLocker lock(&s_lock);
|
||||
s_filesAccepted++;
|
||||
s_recentlyAdded.append(file.filePath());
|
||||
s_recentlyAdded.insert(file.filePath().toLower());
|
||||
lock.unlock();
|
||||
|
||||
waitForPreviousThreads();
|
||||
emit fileAnalyzed(file);
|
||||
}
|
||||
@ -186,14 +195,15 @@ void AnalyzeTask::run_ex(void)
|
||||
qDebug("Rejected file of unknown type: %s", file.filePath().toUtf8().constData());
|
||||
s_filesRejected++;
|
||||
}
|
||||
waitForPreviousThreads();
|
||||
return;
|
||||
}
|
||||
|
||||
//Emit the file now!
|
||||
QWriteLocker lock(&s_lock);
|
||||
s_filesAccepted++;
|
||||
s_recentlyAdded.append(file.filePath());
|
||||
s_recentlyAdded.insert(file.filePath().toLower());
|
||||
lock.unlock();
|
||||
|
||||
waitForPreviousThreads();
|
||||
emit fileAnalyzed(file);
|
||||
}
|
||||
@ -208,7 +218,7 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
|
||||
AudioFileModel audioFile(filePath);
|
||||
|
||||
QReadLocker readLock(&s_lock);
|
||||
if(s_recentlyAdded.contains(filePath, Qt::CaseInsensitive))
|
||||
if(s_recentlyAdded.contains(filePath.toLower()))
|
||||
{
|
||||
*type = fileTypeSkip;
|
||||
return audioFile;
|
||||
@ -726,23 +736,27 @@ void AnalyzeTask::waitForPreviousThreads(void)
|
||||
//This function will block until all threads with a *lower* index have terminated.
|
||||
//Required to make sure that the files will be added in the "correct" order!
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
int retryCount = 0;
|
||||
|
||||
while(retryCount < MAX_RETRIES)
|
||||
{
|
||||
s_waitMutex.lock();
|
||||
|
||||
if((s_threadIdx_finished >= m_threadIdx) || *m_abortFlag)
|
||||
{
|
||||
s_waitMutex.unlock();
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!s_waitCond.wait(&s_waitMutex, 1250))
|
||||
if(!s_waitCond.wait(&s_waitMutex, WAITCOND_TIMEOUT))
|
||||
{
|
||||
qWarning("FileAnalyzerTask: Timeout, retrying!");
|
||||
retryCount++;
|
||||
}
|
||||
|
||||
s_waitMutex.unlock();
|
||||
}
|
||||
|
||||
qWarning("AnalyzeTask Timeout, will proceed anyway !!!");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -797,12 +811,12 @@ int AnalyzeTask::getAdditionalFiles(QStringList &fileList)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AnalyzeTask::waitForOneThread(unsigned long timeout)
|
||||
bool AnalyzeTask::waitForOneThread(void)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
s_waitMutex.lock();
|
||||
ret = s_waitCond.wait(&s_waitMutex, timeout);
|
||||
ret = s_waitCond.wait(&s_waitMutex, WAITCOND_TIMEOUT);
|
||||
s_waitMutex.unlock();
|
||||
|
||||
return ret;
|
||||
@ -825,6 +839,7 @@ void AnalyzeTask::reset(void)
|
||||
s_threadIdx_finished = 0;
|
||||
s_waitMutex.unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// EVENTS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
static unsigned int filesCueSheet(void);
|
||||
|
||||
//Wait till the next running thread terminates
|
||||
static bool waitForOneThread(unsigned long timeout);
|
||||
static bool waitForOneThread(void);
|
||||
|
||||
signals:
|
||||
void fileSelected(const QString &fileName);
|
||||
@ -111,7 +111,7 @@ private:
|
||||
static unsigned int s_filesDenied;
|
||||
static unsigned int s_filesDummyCDDA;
|
||||
static unsigned int s_filesCueSheet;
|
||||
static QStringList s_recentlyAdded;
|
||||
static QSet<QString> s_recentlyAdded;
|
||||
static QStringList s_additionalFiles;
|
||||
|
||||
static unsigned __int64 makeThreadIdx(void);
|
||||
|
Loading…
Reference in New Issue
Block a user