committed by
Jean-Baptiste Kempf
4 changed files with 171 additions and 0 deletions
@ -0,0 +1,103 @@ |
|||
/*****************************************************************************
|
|||
* Copyright (C) 2024 VLC authors and VideoLAN |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* ( at your option ) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|||
*****************************************************************************/ |
|||
|
|||
#include "workerthreadset.hpp" |
|||
|
|||
#include <QTimer> |
|||
|
|||
WorkerThreadSet::~WorkerThreadSet() |
|||
{ |
|||
for (auto worker : workers) |
|||
{ |
|||
if (!worker.thread) |
|||
continue; |
|||
|
|||
finish( worker ); |
|||
} |
|||
} |
|||
|
|||
void WorkerThreadSet::assignToWorkerThread(QObject *obj) |
|||
{ |
|||
auto worker = reserve(); |
|||
obj->moveToThread( worker ); |
|||
|
|||
QObject::connect(obj, &QObject::destroyed, worker, [this, worker]() |
|||
{ |
|||
unreserve( worker ); |
|||
}); |
|||
} |
|||
|
|||
void WorkerThreadSet::finish(Worker &worker) |
|||
{ |
|||
worker.thread->quit(); |
|||
worker.thread->wait(); |
|||
delete worker.thread; |
|||
} |
|||
|
|||
QThread *WorkerThreadSet::reserve() |
|||
{ |
|||
auto itr = std::min_element(std::begin(workers) |
|||
, std::end(workers) |
|||
, [](const Worker &l, const Worker &r) |
|||
{ |
|||
return l.load < r.load; |
|||
}); |
|||
|
|||
assert(itr != std::end(workers)); |
|||
|
|||
if (!itr->thread) |
|||
{ |
|||
itr->thread = new QThread; |
|||
itr->thread->start(); |
|||
} |
|||
|
|||
itr->load++; |
|||
itr->inactiveTime.invalidate(); |
|||
return itr->thread; |
|||
} |
|||
|
|||
void WorkerThreadSet::unreserve(QThread *thread) |
|||
{ |
|||
auto itr = std::find_if(std::begin(workers) |
|||
, std::end(workers) |
|||
, [thread](const Worker &i) { return i.thread == thread; }); |
|||
|
|||
if (itr == std::end(workers)) return; // impossible?
|
|||
|
|||
const int load = --itr->load; |
|||
if (load != 0) |
|||
return; |
|||
|
|||
itr->inactiveTime.start(); |
|||
QTimer::singleShot(CLEANUP_TIMEOUT, this, &WorkerThreadSet::cleanupInactiveWorker); |
|||
} |
|||
|
|||
void WorkerThreadSet::cleanupInactiveWorker() |
|||
{ |
|||
for (auto &worker : workers) |
|||
{ |
|||
if ((worker.load == 0) |
|||
&& worker.inactiveTime.hasExpired(MAX_INACTIVE_TIME) |
|||
&& worker.thread) |
|||
{ |
|||
finish( worker ); |
|||
|
|||
worker.thread = nullptr; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/*****************************************************************************
|
|||
* Copyright (C) 2024 VLC authors and VideoLAN |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* ( at your option ) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
|||
*****************************************************************************/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <QObject> |
|||
#include <QThread> |
|||
|
|||
// maintains a set of reusable worker threads
|
|||
// class is not thread safe and must be accessed from Main thread
|
|||
class WorkerThreadSet : public QObject |
|||
{ |
|||
Q_OBJECT |
|||
public: |
|||
using QObject::QObject; |
|||
|
|||
~WorkerThreadSet(); |
|||
|
|||
// changes the thread affinity of 'obj' to a worker thread
|
|||
void assignToWorkerThread(QObject *obj); |
|||
|
|||
private: |
|||
struct Worker |
|||
{ |
|||
QThread *thread = nullptr; |
|||
int load = 0; |
|||
QElapsedTimer inactiveTime; |
|||
}; |
|||
|
|||
const static int MAX_WORKER = 2; |
|||
const static int CLEANUP_TIMEOUT = 10000; // 10seconds
|
|||
const static int MAX_INACTIVE_TIME = 6000; // 6seconds
|
|||
|
|||
void finish(Worker &worker); |
|||
|
|||
// returns a worker thread after increasing it's load
|
|||
QThread *reserve(); |
|||
|
|||
// reduces load of the previously allocated 'thread'
|
|||
// and makes it available for future operations
|
|||
// threads are automatically freed when they remain
|
|||
// inactive for extended amount of time
|
|||
void unreserve(QThread *thread); |
|||
|
|||
void cleanupInactiveWorker(); |
|||
|
|||
Worker workers[MAX_WORKER] {}; |
|||
}; |
|||
Loading…
Reference in new issue