Make ProcessingDialog use a QThreadPool and, accordingly, make ProcessThread inherit from QRunnable rather than QThread.

This commit is contained in:
LoRd_MuldeR 2013-10-09 03:14:38 +02:00
parent 10001f4ef0
commit 94c199d849
5 changed files with 66 additions and 212 deletions

View File

@ -33,8 +33,8 @@
#define VER_LAMEXP_MINOR_HI 0
#define VER_LAMEXP_MINOR_LO 9
#define VER_LAMEXP_TYPE Alpha
#define VER_LAMEXP_PATCH 1
#define VER_LAMEXP_BUILD 1368
#define VER_LAMEXP_PATCH 2
#define VER_LAMEXP_BUILD 1370
#define VER_LAMEXP_CONFG 1348
///////////////////////////////////////////////////////////////////////////////

View File

@ -60,6 +60,7 @@
#include <QProgressDialog>
#include <QResizeEvent>
#include <QTime>
#include <QThreadPool>
#include <math.h>
#include <float.h>
@ -134,11 +135,11 @@ ProcessingDialog::ProcessingDialog(FileListModel *fileListModel, AudioFileModel
:
QDialog(parent),
ui(new Ui::ProcessingDialog),
//m_aacEncoder(SettingsModel::getAacEncoder()),
m_systemTray(new QSystemTrayIcon(QIcon(":/icons/cd_go.png"), this)),
m_settings(settings),
m_metaInfo(metaInfo),
m_shutdownFlag(shutdownFlag_None),
m_threadPool(NULL),
m_diskObserver(NULL),
m_cpuObserver(NULL),
m_ramObserver(NULL),
@ -315,12 +316,21 @@ ProcessingDialog::~ProcessingDialog(void)
}
}
while(!m_threadList.isEmpty())
//while(!m_threadList.isEmpty())
//{
// ProcessThread *thread = m_threadList.takeFirst();
// thread->terminate();
// thread->wait(15000);
// delete thread;
//}
if(m_threadPool)
{
ProcessThread *thread = m_threadList.takeFirst();
thread->terminate();
thread->wait(15000);
delete thread;
if(!m_threadPool->waitForDone(100))
{
emit abortRunningTasks();
m_threadPool->waitForDone();
}
}
LAMEXP_DELETE(m_progressIndicator);
@ -333,6 +343,7 @@ ProcessingDialog::~ProcessingDialog(void)
LAMEXP_DELETE(m_filterInfoLabelIcon);
LAMEXP_DELETE(m_contextMenu);
LAMEXP_DELETE(m_progressModel);
LAMEXP_DELETE(m_threadPool);
WinSevenTaskbar::setOverlayIcon(this, NULL);
WinSevenTaskbar::setTaskbarState(this, WinSevenTaskbar::WinSevenTaskbarNoState);
@ -510,24 +521,30 @@ void ProcessingDialog::initEncoding(void)
connect(m_ramObserver, SIGNAL(currentUsageChanged(double)), this, SLOT(ramUsageHasChanged(double)), Qt::QueuedConnection);
m_ramObserver->start();
}
unsigned int maximumInstances = qBound(0U, m_settings->maximumInstances(), MAX_INSTANCES);
if(maximumInstances < 1)
if(!m_threadPool)
{
lamexp_cpu_t cpuFeatures = lamexp_detect_cpu_features(lamexp_arguments());
maximumInstances = cores2instances(qBound(1, cpuFeatures.count, 64));
unsigned int maximumInstances = qBound(0U, m_settings->maximumInstances(), MAX_INSTANCES);
if(maximumInstances < 1)
{
lamexp_cpu_t cpuFeatures = lamexp_detect_cpu_features(lamexp_arguments());
maximumInstances = cores2instances(qBound(1, cpuFeatures.count, 64));
}
maximumInstances = qBound(1U, maximumInstances, static_cast<unsigned int>(m_pendingJobs.count()));
if(maximumInstances > 1)
{
m_progressModel->addSystemMessage(tr("Multi-threading enabled: Running %1 instances in parallel!").arg(QString::number(maximumInstances)));
}
m_threadPool = new QThreadPool();
m_threadPool->setMaxThreadCount(maximumInstances);
}
maximumInstances = qBound(1U, maximumInstances, static_cast<unsigned int>(m_pendingJobs.count()));
if(maximumInstances > 1)
{
m_progressModel->addSystemMessage(tr("Multi-threading enabled: Running %1 instances in parallel!").arg(QString::number(maximumInstances)));
}
for(unsigned int i = 0; i < maximumInstances; i++)
for(int i = 0; i < m_threadPool->maxThreadCount(); i++)
{
startNextJob();
qApp->processEvents();
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
}
m_timerStart = lamexp_perfcounter_value();
@ -539,11 +556,7 @@ void ProcessingDialog::abortEncoding(bool force)
if(force) m_forcedAbort = true;
ui->button_AbortProcess->setEnabled(false);
SET_PROGRESS_TEXT(tr("Aborted! Waiting for running jobs to terminate..."));
for(int i = 0; i < m_threadList.count(); i++)
{
m_threadList.at(i)->abort();
}
emit abortRunningTasks();
}
void ProcessingDialog::doneEncoding(void)
@ -557,13 +570,7 @@ void ProcessingDialog::doneEncoding(void)
WinSevenTaskbar::setTaskbarProgress(this, ui->progressBar->value(), ui->progressBar->maximum());
}
int index = m_threadList.indexOf(dynamic_cast<ProcessThread*>(QWidget::sender()));
if(index >= 0)
{
m_threadList.takeAt(index)->deleteLater();
}
if(!m_pendingJobs.isEmpty() && !m_userAborted)
if((!m_pendingJobs.isEmpty()) && (!m_userAborted))
{
startNextJob();
qDebug("Running jobs: %u", m_runningThreads);
@ -595,7 +602,7 @@ void ProcessingDialog::doneEncoding(void)
m_systemTray->showMessage(tr("LameXP - Aborted"), tr("Process was aborted by the user."), QSystemTrayIcon::Warning);
m_systemTray->setIcon(QIcon(":/icons/cd_delete.png"));
QApplication::processEvents();
if(m_settings->soundsEnabled() && !m_forcedAbort)
if(m_settings->soundsEnabled() && (!m_forcedAbort))
{
lamexp_play_sound(IDR_WAVE_ABORTED, false);
}
@ -909,186 +916,24 @@ void ProcessingDialog::startNextJob(void)
thread->setOverwriteMode((m_settings->overwriteMode() == SettingsModel::Overwrite_SkipFile), (m_settings->overwriteMode() == SettingsModel::Overwrite_Replaces));
}
m_threadList.append(thread);
m_allJobs.append(thread->getId());
//Connect thread signals
connect(thread, SIGNAL(finished()), this, SLOT(doneEncoding()), Qt::QueuedConnection);
connect(thread, SIGNAL(processFinished()), this, SLOT(doneEncoding()), Qt::QueuedConnection);
connect(thread, SIGNAL(processStateInitialized(QUuid,QString,QString,int)), m_progressModel, SLOT(addJob(QUuid,QString,QString,int)), Qt::QueuedConnection);
connect(thread, SIGNAL(processStateChanged(QUuid,QString,int)), m_progressModel, SLOT(updateJob(QUuid,QString,int)), Qt::QueuedConnection);
connect(thread, SIGNAL(processStateFinished(QUuid,QString,int)), this, SLOT(processFinished(QUuid,QString,int)), Qt::QueuedConnection);
connect(thread, SIGNAL(processMessageLogged(QUuid,QString)), m_progressModel, SLOT(appendToLog(QUuid,QString)), Qt::QueuedConnection);
connect(this, SIGNAL(abortRunningTasks()), thread, SLOT(abort()), Qt::DirectConnection);
//Give it a go!
m_runningThreads++;
thread->start();
m_threadPool->start(thread);
//Give thread some advance
for(unsigned int i = 0; i < MAX_INSTANCES; i++)
{
QThread::yieldCurrentThread();
}
lamexp_sleep(1);
}
//AbstractEncoder *ProcessingDialog::makeEncoder(bool *nativeResampling)
//{
// int rcMode = -1;
// AbstractEncoder *encoder = NULL;
// *nativeResampling = false;
//
// switch(m_settings->compressionEncoder())
// {
// /*-------- MP3Encoder /*--------*/
// case SettingsModel::MP3Encoder:
// {
// MP3Encoder *mp3Encoder = new MP3Encoder();
// mp3Encoder->setRCMode(rcMode = m_settings->compressionRCModeLAME());
// mp3Encoder->setBitrate(IS_VBR(rcMode) ? m_settings->compressionVbrLevelLAME() : m_settings->compressionBitrateLAME());
// mp3Encoder->setAlgoQuality(m_settings->lameAlgoQuality());
// if(m_settings->bitrateManagementEnabled())
// {
// mp3Encoder->setBitrateLimits(m_settings->bitrateManagementMinRate(), m_settings->bitrateManagementMaxRate());
// }
// if(m_settings->samplingRate() > 0)
// {
// mp3Encoder->setSamplingRate(SettingsModel::samplingRates[m_settings->samplingRate()]);
// *nativeResampling = true;
// }
// mp3Encoder->setChannelMode(m_settings->lameChannelMode());
// mp3Encoder->setCustomParams(m_settings->customParametersLAME());
// encoder = mp3Encoder;
// }
// break;
// /*-------- VorbisEncoder /*--------*/
// case SettingsModel::VorbisEncoder:
// {
// VorbisEncoder *vorbisEncoder = new VorbisEncoder();
// vorbisEncoder->setRCMode(rcMode = m_settings->compressionRCModeOggEnc());
// vorbisEncoder->setBitrate(IS_VBR(rcMode) ? m_settings->compressionVbrLevelOggEnc() : m_settings->compressionBitrateOggEnc());
// if(m_settings->bitrateManagementEnabled())
// {
// vorbisEncoder->setBitrateLimits(m_settings->bitrateManagementMinRate(), m_settings->bitrateManagementMaxRate());
// }
// if(m_settings->samplingRate() > 0)
// {
// vorbisEncoder->setSamplingRate(SettingsModel::samplingRates[m_settings->samplingRate()]);
// *nativeResampling = true;
// }
// vorbisEncoder->setCustomParams(m_settings->customParametersOggEnc());
// encoder = vorbisEncoder;
// }
// break;
// /*-------- AACEncoder /*--------*/
// case SettingsModel::AACEncoder:
// {
// switch(m_aacEncoder)
// {
// case SettingsModel::AAC_ENCODER_QAAC:
// {
// QAACEncoder *aacEncoder = new QAACEncoder();
// aacEncoder->setRCMode(rcMode = m_settings->compressionRCModeAacEnc());
// aacEncoder->setBitrate(IS_VBR(rcMode) ? m_settings->compressionVbrLevelAacEnc() : m_settings->compressionBitrateAacEnc());
// aacEncoder->setProfile(m_settings->aacEncProfile());
// aacEncoder->setCustomParams(m_settings->customParametersAacEnc());
// encoder = aacEncoder;
// }
// break;
// case SettingsModel::AAC_ENCODER_FHG:
// {
// FHGAACEncoder *aacEncoder = new FHGAACEncoder();
// aacEncoder->setRCMode(rcMode = m_settings->compressionRCModeAacEnc());
// aacEncoder->setBitrate(IS_VBR(rcMode) ? m_settings->compressionVbrLevelAacEnc() : m_settings->compressionBitrateAacEnc());
// aacEncoder->setProfile(m_settings->aacEncProfile());
// aacEncoder->setCustomParams(m_settings->customParametersAacEnc());
// encoder = aacEncoder;
// }
// break;
// case SettingsModel::AAC_ENCODER_NERO:
// {
// AACEncoder *aacEncoder = new AACEncoder();
// aacEncoder->setRCMode(rcMode = m_settings->compressionRCModeAacEnc());
// aacEncoder->setBitrate(IS_VBR(rcMode) ? m_settings->compressionVbrLevelAacEnc() : m_settings->compressionBitrateAacEnc());
// aacEncoder->setEnable2Pass(m_settings->neroAACEnable2Pass());
// aacEncoder->setProfile(m_settings->aacEncProfile());
// aacEncoder->setCustomParams(m_settings->customParametersAacEnc());
// encoder = aacEncoder;
// }
// break;
// default:
// throw "makeEncoder(): Unknown AAC encoder specified!";
// break;
// }
// }
// break;
// /*-------- AC3Encoder /*--------*/
// case SettingsModel::AC3Encoder:
// {
// AC3Encoder *ac3Encoder = new AC3Encoder();
// ac3Encoder->setRCMode(rcMode = m_settings->compressionRCModeAften());
// ac3Encoder->setBitrate(IS_VBR(rcMode) ? m_settings->compressionVbrLevelAften() : m_settings->compressionBitrateAften());
// ac3Encoder->setCustomParams(m_settings->customParametersAften());
// ac3Encoder->setAudioCodingMode(m_settings->aftenAudioCodingMode());
// ac3Encoder->setDynamicRangeCompression(m_settings->aftenDynamicRangeCompression());
// ac3Encoder->setExponentSearchSize(m_settings->aftenExponentSearchSize());
// ac3Encoder->setFastBitAllocation(m_settings->aftenFastBitAllocation());
// encoder = ac3Encoder;
// }
// break;
// /*-------- FLACEncoder /*--------*/
// case SettingsModel::FLACEncoder:
// {
// FLACEncoder *flacEncoder = new FLACEncoder();
// flacEncoder->setBitrate(m_settings->compressionVbrLevelFLAC());
// flacEncoder->setRCMode(SettingsModel::VBRMode);
// flacEncoder->setCustomParams(m_settings->customParametersFLAC());
// encoder = flacEncoder;
// }
// break;
// /*-------- OpusEncoder --------*/
// case SettingsModel::OpusEncoder:
// {
// OpusEncoder *opusEncoder = new OpusEncoder();
// opusEncoder->setRCMode(rcMode = m_settings->compressionRCModeOpusEnc());
// opusEncoder->setBitrate(m_settings->compressionBitrateOpusEnc()); /*Opus always uses bitrate*/
// opusEncoder->setOptimizeFor(m_settings->opusOptimizeFor());
// opusEncoder->setEncodeComplexity(m_settings->opusComplexity());
// opusEncoder->setFrameSize(m_settings->opusFramesize());
// opusEncoder->setCustomParams(m_settings->customParametersOpus());
// encoder = opusEncoder;
// }
// break;
// /*-------- DCAEncoder --------*/
// case SettingsModel::DCAEncoder:
// {
// DCAEncoder *dcaEncoder = new DCAEncoder();
// dcaEncoder->setRCMode(SettingsModel::CBRMode);
// dcaEncoder->setBitrate(IS_VBR(rcMode) ? 0 : m_settings->compressionBitrateDcaEnc());
// encoder = dcaEncoder;
// }
// break;
// /*-------- PCMEncoder --------*/
// case SettingsModel::PCMEncoder:
// {
// WaveEncoder *waveEncoder = new WaveEncoder();
// waveEncoder->setBitrate(0); /*does NOT apply to PCM output*/
// waveEncoder->setRCMode(0); /*does NOT apply to PCM output*/
// encoder = waveEncoder;
// }
// break;
// /*-------- default --------*/
// default:
// throw "Unsupported encoder!";
// }
//
// //Sanity checking
// if(!encoder)
// {
// throw "No encoder instance has been assigend!";
// }
//
// return encoder;
//}
void ProcessingDialog::writePlayList(void)
{
if(m_succeededJobs.count() <= 0 || m_allJobs.count() <= 0)

View File

@ -40,6 +40,7 @@ class QModelIndex;
class QMovie;
class RAMObserverThread;
class SettingsModel;
class QThreadPool;
enum shutdownFlag_t
{
@ -82,6 +83,9 @@ private slots:
void diskUsageHasChanged(const quint64 val);
void progressViewFilterChanged(void);
signals:
void abortRunningTasks(void);
protected:
void showEvent(QShowEvent *event);
void closeEvent(QCloseEvent *event);
@ -99,10 +103,10 @@ private:
bool shutdownComputer(void);
QString time2text(const double timeVal) const;
QThreadPool *m_threadPool;
QList<AudioFileModel> m_pendingJobs;
SettingsModel *m_settings;
AudioFileModel *m_metaInfo;
QList<ProcessThread*> m_threadList;
QMovie *m_progressIndicator;
ProgressModel *m_progressModel;
QMap<QUuid,QString> m_playList;
@ -126,7 +130,4 @@ private:
DiskObserverThread *m_diskObserver;
qint64 m_timerStart;
int m_progressViewFilter;
//const int m_aacEncoder;
//AbstractEncoder *makeEncoder(bool *nativeResampling);
};

View File

@ -96,6 +96,8 @@ ProcessThread::~ProcessThread(void)
LAMEXP_DELETE(m_encoder);
LAMEXP_DELETE(m_propDetect);
emit processFinished();
}
////////////////////////////////////////////////////////////
@ -121,9 +123,12 @@ void ProcessThread::processFile()
{
m_aborted = false;
bool bSuccess = true;
//Initialize job status
qDebug("Process thread %s has started.", m_jobId.toString().toLatin1().constData());
emit processStateInitialized(m_jobId, QFileInfo(m_audioFile.filePath()).fileName(), tr("Starting..."), ProgressModel::JobRunning);
//Initialize log
handleMessage(QString().sprintf("LameXP v%u.%02u (Build #%u), compiled on %s at %s", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build(), lamexp_version_date().toString(Qt::ISODate).toLatin1().constData(), lamexp_version_time()));
handleMessage("\n-------------------------------\n");
@ -269,7 +274,7 @@ void ProcessThread::processFile()
bSuccess = fileInfo.exists() && fileInfo.isFile() && (fileInfo.size() > 0);
}
QThread::msleep(125);
lamexp_sleep(125);
//Report result
emit processStateChanged(m_jobId, (m_aborted ? tr("Aborted!") : (bSuccess ? tr("Done.") : tr("Failed!"))), ((bSuccess && !m_aborted) ? ProgressModel::JobComplete : ProgressModel::JobFailed));
@ -407,7 +412,7 @@ int ProcessThread::generateOutFileName(QString &outFileName)
{
bOkay = QFile::remove(outFileName);
if(bOkay) break;
QThread::msleep(125);
lamexp_sleep(125);
}
if(QFileInfo(outFileName).exists() || (!bOkay))
{

View File

@ -21,7 +21,7 @@
#pragma once
#include <QThread>
#include <QRunnable>
#include <QUuid>
#include <QStringList>
@ -32,7 +32,7 @@ class QMutex;
class AbstractFilter;
class WaveProperties;
class ProcessThread: public QThread
class ProcessThread: public QObject, public QRunnable
{
Q_OBJECT
@ -40,14 +40,16 @@ public:
ProcessThread(const AudioFileModel &audioFile, const QString &outputDirectory, const QString &tempDirectory, AbstractEncoder *encoder, const bool prependRelativeSourcePath);
~ProcessThread(void);
void run();
void run(void);
void abort() { m_aborted = true; }
QUuid getId() { return m_jobId; }
QUuid getId(void) { return m_jobId; }
void setRenamePattern(const QString &pattern);
void setOverwriteMode(const bool bSkipExistingFile, const bool ReplacesExisting = false);
void addFilter(AbstractFilter *filter);
public slots:
void abort(void) { m_aborted = true; }
private slots:
void handleUpdate(int progress);
void handleMessage(const QString &line);
@ -57,6 +59,7 @@ signals:
void processStateChanged(const QUuid &jobId, const QString &newStatus, int newState);
void processStateFinished(const QUuid &jobId, const QString &outFileName, int success);
void processMessageLogged(const QUuid &jobId, const QString &line);
void processFinished(void);
private:
enum ProcessStep