diff --git a/libs/image/kis_update_job_item.h b/libs/image/kis_update_job_item.h --- a/libs/image/kis_update_job_item.h +++ b/libs/image/kis_update_job_item.h @@ -70,8 +70,8 @@ setDone(); - emit sigDoSomeUsefulWork(); emit sigJobFinished(); + emit sigDoSomeUsefulWork(); m_exclusiveJobLock->unlock(); } diff --git a/libs/image/kis_update_scheduler.cpp b/libs/image/kis_update_scheduler.cpp --- a/libs/image/kis_update_scheduler.cpp +++ b/libs/image/kis_update_scheduler.cpp @@ -55,15 +55,19 @@ KisSimpleUpdateQueue updatesQueue; KisStrokesQueue strokesQueue; - KisUpdaterContext updaterContext; bool processingBlocked = false; qreal balancingRatio = 1.0; // updates-queue-size/strokes-queue-size KisProjectionUpdateListener *projectionUpdateListener; KisQueuesProgressUpdater *progressUpdater = 0; QAtomicInt updatesLockCounter; QReadWriteLock updatesStartLock; KisLazyWaitCondition updatesFinishedCondition; + + // KisUpdaterContext can emit signals to KisUpdateScheduler in the dtor, so it + // must to be deleted before anything else. + // That means updaterContext must be declared last. + KisUpdaterContext updaterContext; }; KisUpdateScheduler::KisUpdateScheduler(KisProjectionUpdateListener *projectionUpdateListener) diff --git a/libs/image/kis_updater_context.h b/libs/image/kis_updater_context.h --- a/libs/image/kis_updater_context.h +++ b/libs/image/kis_updater_context.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "kis_base_rects_walker.h" #include "kis_async_merger.h" @@ -128,7 +129,11 @@ protected: static bool walkerIntersectsJob(KisBaseRectsWalkerSP walker, const KisUpdateJobItem* job); + + qint32 defaultThreadCount() const; + qint32 findSpareThread(); + void startJob(KisUpdateJobItem* job); protected: /** @@ -141,6 +146,7 @@ QMutex m_lock; QVector m_jobs; + QSemaphore m_waitSema; QThreadPool m_threadPool; KisLockFreeLodCounter m_lodCounter; }; diff --git a/libs/image/kis_updater_context.cpp b/libs/image/kis_updater_context.cpp --- a/libs/image/kis_updater_context.cpp +++ b/libs/image/kis_updater_context.cpp @@ -25,14 +25,10 @@ #include "kis_stroke_job.h" -KisUpdaterContext::KisUpdaterContext(qint32 threadCount) +KisUpdaterContext::KisUpdaterContext(qint32 threadCount): + m_jobs(threadCount > 0 ? threadCount : defaultThreadCount()), + m_waitSema(m_jobs.size()) { - if(threadCount <= 0) { - threadCount = QThread::idealThreadCount(); - threadCount = threadCount > 0 ? threadCount : 1; - } - - m_jobs.resize(threadCount); for(qint32 i = 0; i < m_jobs.size(); i++) { m_jobs[i] = new KisUpdateJobItem(&m_exclusiveJobLock); connect(m_jobs[i], SIGNAL(sigContinueUpdate(const QRect&)), @@ -54,6 +50,12 @@ delete m_jobs[i]; } +qint32 KisUpdaterContext::defaultThreadCount() const +{ + int threadCount = QThread::idealThreadCount(); + return threadCount > 0 ? threadCount : 1; +} + void KisUpdaterContext::getJobsSnapshot(qint32 &numMergeJobs, qint32 &numStrokeJobs) { @@ -121,7 +123,7 @@ Q_ASSERT(jobIndex >= 0); m_jobs[jobIndex]->setWalker(walker); - m_threadPool.start(m_jobs[jobIndex]); + startJob(m_jobs[jobIndex]); } /** @@ -144,7 +146,7 @@ Q_ASSERT(jobIndex >= 0); m_jobs[jobIndex]->setStrokeJob(strokeJob); - m_threadPool.start(m_jobs[jobIndex]); + startJob(m_jobs[jobIndex]); } /** @@ -167,7 +169,7 @@ Q_ASSERT(jobIndex >= 0); m_jobs[jobIndex]->setSpontaneousJob(spontaneousJob); - m_threadPool.start(m_jobs[jobIndex]); + startJob(m_jobs[jobIndex]); } /** @@ -185,7 +187,9 @@ void KisUpdaterContext::waitForDone() { - m_threadPool.waitForDone(); + qint32 allJobs = m_jobs.size(); + m_waitSema.acquire(allJobs); + m_waitSema.release(allJobs); } bool KisUpdaterContext::walkerIntersectsJob(KisBaseRectsWalkerSP walker, @@ -204,9 +208,17 @@ return -1; } + +void KisUpdaterContext::startJob(KisUpdateJobItem* job) +{ + m_waitSema.acquire(); + m_threadPool.start(job); +} + void KisUpdaterContext::slotJobFinished() { m_lodCounter.removeLod(); + m_waitSema.release(); // Be careful. This slot can be called asynchronously without locks. emit sigSpareThreadAppeared();