Fix an edge case where m_remainingItems has elements but we don't have more workers to consume it

This commit is contained in:
David Capello 2019-03-26 15:19:52 -03:00
parent dbae196f2d
commit 30798435d1
2 changed files with 38 additions and 15 deletions

View File

@ -203,6 +203,13 @@ ThumbnailGenerator* ThumbnailGenerator::instance()
return singleton; return singleton;
} }
ThumbnailGenerator::ThumbnailGenerator()
{
int n = std::thread::hardware_concurrency()-1;
if (n < 1) n = 1;
m_maxWorkers = n;
}
bool ThumbnailGenerator::checkWorkers() bool ThumbnailGenerator::checkWorkers()
{ {
base::scoped_lock hold(m_workersAccess); base::scoped_lock hold(m_workersAccess);
@ -231,17 +238,31 @@ void ThumbnailGenerator::generateThumbnail(IFileItem* fileitem)
return; return;
if (fileitem->getThumbnailProgress() > 0.0) { if (fileitem->getThumbnailProgress() > 0.0) {
if (fileitem->getThumbnailProgress() < 0.0002) { if (fileitem->getThumbnailProgress() == 0.00001) {
m_remainingItems.prioritize( m_remainingItems.prioritize(
[fileitem](const Item& item) { [fileitem](const Item& item) {
return (item.fileitem == fileitem); return (item.fileitem == fileitem);
}); });
// If there is no more workers running, we have to start a new
// one to process the m_remainingItems queue. How is it possible
// that a IFileItem has a thumbnail progress == 0.00001 but
// there is no workers? This is an edge case where:
// 1. The Worker::loadBgThread() asks for the queue of remaining items
// and it's empty, so the thread is going to be closed
// 2. We've just created a FOP for this IFileItem and ask for
// available workers and we've already launch the max quantity
// of possible workers (m_maxWorkers)
// 3. All worker threads are just closed so there is no more
// worker for the remaining item in the queue.
if (m_workers.empty())
startWorker();
} }
return; return;
} }
// Set a starting progress so we don't enqueue the same item two times. // Set a starting progress so we don't enqueue the same item two times.
fileitem->setThumbnailProgress(0.0001); fileitem->setThumbnailProgress(0.00001);
THUMB_TRACE("Queue FOP thumbnail for %s\n", THUMB_TRACE("Queue FOP thumbnail for %s\n",
fileitem->fileName().c_str()); fileitem->fileName().c_str());
@ -261,19 +282,7 @@ void ThumbnailGenerator::generateThumbnail(IFileItem* fileitem)
m_remainingItems.push(Item(fileitem, fop.get())); m_remainingItems.push(Item(fileitem, fop.get()));
fop.release(); fop.release();
int n = std::thread::hardware_concurrency()-1; startWorker();
if (n < 1) n = 1;
if (m_workers.size() < n) {
Worker* worker = new Worker(m_remainingItems);
try {
base::scoped_lock hold(m_workersAccess);
m_workers.push_back(worker);
}
catch (...) {
delete worker;
throw;
}
}
} }
void ThumbnailGenerator::stopAllWorkers() void ThumbnailGenerator::stopAllWorkers()
@ -296,4 +305,14 @@ void ThumbnailGenerator::stopAllWorkers()
worker->stop(); worker->stop();
} }
void ThumbnailGenerator::startWorker()
{
base::scoped_lock hold(m_workersAccess);
if (m_workers.size() < m_maxWorkers) {
std::unique_ptr<Worker> worker(new Worker(m_remainingItems));
m_workers.push_back(worker.get());
worker.release();
}
}
} // namespace app } // namespace app

View File

@ -24,6 +24,7 @@ namespace app {
class IFileItem; class IFileItem;
class ThumbnailGenerator { class ThumbnailGenerator {
ThumbnailGenerator();
public: public:
static ThumbnailGenerator* instance(); static ThumbnailGenerator* instance();
@ -43,6 +44,8 @@ namespace app {
void stopAllWorkers(); void stopAllWorkers();
private: private:
void startWorker();
class Worker; class Worker;
typedef std::vector<Worker*> WorkerList; typedef std::vector<Worker*> WorkerList;
@ -56,6 +59,7 @@ namespace app {
} }
}; };
int m_maxWorkers;
WorkerList m_workers; WorkerList m_workers;
base::mutex m_workersAccess; base::mutex m_workersAccess;
std::unique_ptr<base::thread> m_stopThread; std::unique_ptr<base::thread> m_stopThread;