mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 10:22:48 +00:00
generic: replace QThreadPool and QRunnable with custom class
on a side note it does not solve any thread-safety issues, such are out of the scope of the class Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
747c37269b
commit
2f485d5376
9 changed files with 271 additions and 26 deletions
|
@ -251,6 +251,7 @@ install(
|
||||||
KTempDir
|
KTempDir
|
||||||
KTemporaryFile
|
KTemporaryFile
|
||||||
KTextEdit
|
KTextEdit
|
||||||
|
KThreadPool
|
||||||
KTimeEdit
|
KTimeEdit
|
||||||
KTimeZone
|
KTimeZone
|
||||||
KTimerDialog
|
KTimerDialog
|
||||||
|
|
1
includes/KThreadPool
Normal file
1
includes/KThreadPool
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "../kthreadpool.h"
|
|
@ -72,6 +72,7 @@ set(kdecore_LIB_SRCS
|
||||||
kernel/kglobal.cpp
|
kernel/kglobal.cpp
|
||||||
kernel/kcomponentdata.cpp
|
kernel/kcomponentdata.cpp
|
||||||
kernel/kstandarddirs.cpp
|
kernel/kstandarddirs.cpp
|
||||||
|
kernel/kthreadpool.cpp
|
||||||
services/kmimetypefactory.cpp
|
services/kmimetypefactory.cpp
|
||||||
services/kmimemagicrule.cpp
|
services/kmimemagicrule.cpp
|
||||||
services/kmimetypetrader.cpp
|
services/kmimetypetrader.cpp
|
||||||
|
@ -218,6 +219,7 @@ install(
|
||||||
kernel/kglobal.h
|
kernel/kglobal.h
|
||||||
kernel/kcomponentdata.h
|
kernel/kcomponentdata.h
|
||||||
kernel/kstandarddirs.h
|
kernel/kstandarddirs.h
|
||||||
|
kernel/kthreadpool.h
|
||||||
services/kmimetype.h
|
services/kmimetype.h
|
||||||
services/kmimetypetrader.h
|
services/kmimetypetrader.h
|
||||||
services/kservice.h
|
services/kservice.h
|
||||||
|
|
162
kdecore/kernel/kthreadpool.cpp
Normal file
162
kdecore/kernel/kthreadpool.cpp
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
This file is part of the KDE libraries
|
||||||
|
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kthreadpool.h"
|
||||||
|
#include "kdebug.h"
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QAtomicInt>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
|
static const int s_waittimeout = 100;
|
||||||
|
static const int s_terminatetimeout = 5000;
|
||||||
|
|
||||||
|
class KThreadPoolPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KThreadPoolPrivate(KThreadPool *parent);
|
||||||
|
|
||||||
|
void appendThread(QThread *thread);
|
||||||
|
|
||||||
|
void _k_slotFinished();
|
||||||
|
|
||||||
|
QMutex mutex;
|
||||||
|
KThreadPool* parent;
|
||||||
|
int maxthreads;
|
||||||
|
QAtomicInt activethreadcount;
|
||||||
|
QList<QThread*> activethreads;
|
||||||
|
QList<QThread*> queuedthreads;
|
||||||
|
};
|
||||||
|
|
||||||
|
KThreadPoolPrivate::KThreadPoolPrivate(KThreadPool *_parent)
|
||||||
|
: parent(_parent),
|
||||||
|
maxthreads(QThread::idealThreadCount()),
|
||||||
|
activethreadcount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThreadPoolPrivate::appendThread(QThread *thread)
|
||||||
|
{
|
||||||
|
activethreadcount.ref();
|
||||||
|
activethreads.append(thread);
|
||||||
|
parent->connect(
|
||||||
|
thread, SIGNAL(finished()),
|
||||||
|
parent, SLOT(_k_slotFinished())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThreadPoolPrivate::_k_slotFinished()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
QMutableListIterator<QThread*> iter(activethreads);
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
QThread* thread = iter.next();
|
||||||
|
if (thread->isFinished()) {
|
||||||
|
kDebug() << "thread finished" << thread;
|
||||||
|
iter.remove();
|
||||||
|
activethreadcount.deref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!queuedthreads.isEmpty()) {
|
||||||
|
QThread* thread = queuedthreads.takeFirst();
|
||||||
|
kDebug() << "starting thread from queue" << thread;
|
||||||
|
appendThread(thread);
|
||||||
|
locker.unlock();
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KThreadPool::KThreadPool(QObject *parent)
|
||||||
|
: QObject(parent ? parent : qApp),
|
||||||
|
d(new KThreadPoolPrivate(this))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
KThreadPool::~KThreadPool()
|
||||||
|
{
|
||||||
|
waitForDone();
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThreadPool::start(QThread *thread, const QThread::Priority priority)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&d->mutex);
|
||||||
|
if (d->activethreadcount >= d->maxthreads) {
|
||||||
|
kDebug() << "too many threads active, putting thread in queue" << thread;
|
||||||
|
d->queuedthreads.append(thread);
|
||||||
|
} else {
|
||||||
|
kDebug() << "starting thread" << thread;
|
||||||
|
d->appendThread(thread);
|
||||||
|
locker.unlock();
|
||||||
|
thread->start(priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThreadPool::waitForDone(const int timeout)
|
||||||
|
{
|
||||||
|
kDebug() << "waiting for threads" << timeout;
|
||||||
|
QMutexLocker locker(&d->mutex);
|
||||||
|
QElapsedTimer elapsedtimer;
|
||||||
|
elapsedtimer.start();
|
||||||
|
QMutableListIterator<QThread*> iter(d->activethreads);
|
||||||
|
kDebug() << "currently" << d->activethreads << "active threads";
|
||||||
|
while ((timeout < 1 || elapsedtimer.elapsed() < timeout) && d->activethreadcount > 0) {
|
||||||
|
iter.toFront();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
QThread* thread = iter.next();
|
||||||
|
// kDebug() << "waiting for" << thread;
|
||||||
|
disconnect(thread, 0, this, 0);
|
||||||
|
thread->wait(s_waittimeout);
|
||||||
|
if (thread->isFinished()) {
|
||||||
|
kDebug() << "thread finished" << thread;
|
||||||
|
iter.remove();
|
||||||
|
d->activethreadcount.deref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d->activethreadcount > 0) {
|
||||||
|
kWarning() << "still there are active threads" << d->activethreadcount;
|
||||||
|
iter.toFront();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
QThread* thread = iter.next();
|
||||||
|
kWarning() << "terminating" << thread;
|
||||||
|
thread->terminate();
|
||||||
|
thread->wait(s_terminatetimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int KThreadPool::maxThreadCount() const
|
||||||
|
{
|
||||||
|
return d->maxthreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThreadPool::setMaxThreadCount(int count)
|
||||||
|
{
|
||||||
|
d->maxthreads = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int KThreadPool::activeThreadCount() const
|
||||||
|
{
|
||||||
|
return d->activethreadcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_kthreadpool.cpp"
|
59
kdecore/kernel/kthreadpool.h
Normal file
59
kdecore/kernel/kthreadpool.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
This file is part of the KDE libraries
|
||||||
|
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KTHREADPOOL_H
|
||||||
|
#define KTHREADPOOL_H
|
||||||
|
|
||||||
|
#include <kdecore_export.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
class KThreadPoolPrivate;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Thread pool class
|
||||||
|
|
||||||
|
@since 4.24
|
||||||
|
@warning the API is subject to change
|
||||||
|
*/
|
||||||
|
class KDECORE_EXPORT KThreadPool : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
KThreadPool(QObject *parent = nullptr);
|
||||||
|
~KThreadPool();
|
||||||
|
|
||||||
|
void start(QThread *thread, const QThread::Priority priority = QThread::InheritPriority);
|
||||||
|
void waitForDone(const int timeout = 30000);
|
||||||
|
|
||||||
|
int maxThreadCount() const;
|
||||||
|
void setMaxThreadCount(int count);
|
||||||
|
|
||||||
|
int activeThreadCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(KThreadPool);
|
||||||
|
KThreadPoolPrivate *const d;
|
||||||
|
|
||||||
|
Q_PRIVATE_SLOT(d, void _k_slotFinished());
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KTHREADPOOL_H
|
|
@ -18,10 +18,9 @@
|
||||||
|
|
||||||
#include "khttp.h"
|
#include "khttp.h"
|
||||||
#include "klocale.h"
|
#include "klocale.h"
|
||||||
|
#include "kthreadpool.h"
|
||||||
#include "kdebug.h"
|
#include "kdebug.h"
|
||||||
|
|
||||||
#include <QRunnable>
|
|
||||||
#include <QThreadPool>
|
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
@ -380,10 +379,11 @@ void KHTTPHeadersParser::parseHeaders(const QByteArray &header, const bool authe
|
||||||
// qDebug() << Q_FUNC_INFO << m_method << m_path << m_version << m_authuser << m_authpass;
|
// qDebug() << Q_FUNC_INFO << m_method << m_path << m_version << m_authuser << m_authpass;
|
||||||
}
|
}
|
||||||
|
|
||||||
class KHTTPRunnable : public QRunnable
|
class KHTTPThread : public QThread
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
KHTTPRunnable(QFile *file, QTcpSocket *client, QAtomicInt *ref);
|
KHTTPThread(QObject *parent, QFile *file, QTcpSocket *client, QAtomicInt *ref);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void run() final;
|
void run() final;
|
||||||
|
@ -394,15 +394,15 @@ private:
|
||||||
QAtomicInt* m_ref;
|
QAtomicInt* m_ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
KHTTPRunnable::KHTTPRunnable(QFile *file, QTcpSocket *client, QAtomicInt *ref)
|
KHTTPThread::KHTTPThread(QObject *parent, QFile *file, QTcpSocket *client, QAtomicInt *ref)
|
||||||
: QRunnable(),
|
: QThread(parent),
|
||||||
m_file(file),
|
m_file(file),
|
||||||
m_client(client),
|
m_client(client),
|
||||||
m_ref(ref)
|
m_ref(ref)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void KHTTPRunnable::run()
|
void KHTTPThread::run()
|
||||||
{
|
{
|
||||||
QByteArray httpbuffer(KHTTP_BUFFSIZE, '\0');
|
QByteArray httpbuffer(KHTTP_BUFFSIZE, '\0');
|
||||||
qint64 httpfileresult = m_file->read(httpbuffer.data(), httpbuffer.size());
|
qint64 httpfileresult = m_file->read(httpbuffer.data(), httpbuffer.size());
|
||||||
|
@ -460,7 +460,7 @@ private:
|
||||||
void writeResponse(const ushort httpstatus, const bool authenticate, QTcpSocket *client, const bool get);
|
void writeResponse(const ushort httpstatus, const bool authenticate, QTcpSocket *client, const bool get);
|
||||||
|
|
||||||
QAtomicInt m_ref;
|
QAtomicInt m_ref;
|
||||||
QThreadPool* m_filepool;
|
KThreadPool* m_filepool;
|
||||||
};
|
};
|
||||||
|
|
||||||
KHTTPPrivate::KHTTPPrivate(QObject *parent)
|
KHTTPPrivate::KHTTPPrivate(QObject *parent)
|
||||||
|
@ -472,7 +472,7 @@ KHTTPPrivate::KHTTPPrivate(QObject *parent)
|
||||||
serverid = QCoreApplication::applicationName();
|
serverid = QCoreApplication::applicationName();
|
||||||
|
|
||||||
// NOTE: the default thread limit is number of CPU cores online
|
// NOTE: the default thread limit is number of CPU cores online
|
||||||
m_filepool = new QThreadPool(this);
|
m_filepool = new KThreadPool(this);
|
||||||
|
|
||||||
// NOTE: the default maximum for pending connections is 30
|
// NOTE: the default maximum for pending connections is 30
|
||||||
tcpserver = new QTcpServer(this);
|
tcpserver = new QTcpServer(this);
|
||||||
|
@ -567,7 +567,7 @@ void KHTTPPrivate::slotNewConnection()
|
||||||
client->flush();
|
client->flush();
|
||||||
|
|
||||||
if (get) {
|
if (get) {
|
||||||
m_filepool->start(new KHTTPRunnable(httpfile, client, &m_ref));
|
m_filepool->start(new KHTTPThread(m_filepool, httpfile, client, &m_ref));
|
||||||
} else {
|
} else {
|
||||||
kDebug(s_khttpdebugarea) << "done with client" << client->peerAddress() << client->peerPort();
|
kDebug(s_khttpdebugarea) << "done with client" << client->peerAddress() << client->peerPort();
|
||||||
client->disconnectFromHost();
|
client->disconnectFromHost();
|
||||||
|
|
|
@ -18,13 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "runnerjobs_p.h"
|
#include "runnerjobs_p.h"
|
||||||
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include <kdebug.h>
|
|
||||||
|
|
||||||
#include "runnermanager.h"
|
#include "runnermanager.h"
|
||||||
#include "plasma/querymatch.h"
|
#include "plasma/querymatch.h"
|
||||||
|
#include "kdebug.h"
|
||||||
|
|
||||||
namespace Plasma {
|
namespace Plasma {
|
||||||
|
|
||||||
|
@ -34,7 +30,7 @@ namespace Plasma {
|
||||||
|
|
||||||
FindMatchesJob::FindMatchesJob(Plasma::AbstractRunner *runner,
|
FindMatchesJob::FindMatchesJob(Plasma::AbstractRunner *runner,
|
||||||
Plasma::RunnerContext *context)
|
Plasma::RunnerContext *context)
|
||||||
: QRunnable(),
|
: QThread(runner),
|
||||||
m_context(*context, 0),
|
m_context(*context, 0),
|
||||||
m_runner(runner)
|
m_runner(runner)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QRunnable>
|
#include <QThread>
|
||||||
|
|
||||||
#include "abstractrunner.h"
|
#include "abstractrunner.h"
|
||||||
|
|
||||||
|
@ -33,8 +33,9 @@ namespace Plasma {
|
||||||
* FindMatchesJob class
|
* FindMatchesJob class
|
||||||
* Class to run queries in different threads
|
* Class to run queries in different threads
|
||||||
*/
|
*/
|
||||||
class FindMatchesJob : public QRunnable
|
class FindMatchesJob : public QThread
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FindMatchesJob(Plasma::AbstractRunner *runner,
|
FindMatchesJob(Plasma::AbstractRunner *runner,
|
||||||
Plasma::RunnerContext *context);
|
Plasma::RunnerContext *context);
|
||||||
|
|
|
@ -25,12 +25,12 @@
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QThreadPool>
|
|
||||||
|
|
||||||
#include <kdebug.h>
|
#include "kplugininfo.h"
|
||||||
#include <kplugininfo.h>
|
#include "kservicetypetrader.h"
|
||||||
#include <kservicetypetrader.h>
|
#include "kstandarddirs.h"
|
||||||
#include <kstandarddirs.h>
|
#include "kthreadpool.h"
|
||||||
|
#include "kdebug.h"
|
||||||
|
|
||||||
// #define MEASURE_PREPTIME
|
// #define MEASURE_PREPTIME
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
allRunnersPrepped(false),
|
allRunnersPrepped(false),
|
||||||
teardownRequested(false)
|
teardownRequested(false)
|
||||||
{
|
{
|
||||||
threadPool = new QThreadPool();
|
threadPool = new KThreadPool(q);
|
||||||
|
|
||||||
matchChangeTimer.setSingleShot(true);
|
matchChangeTimer.setSingleShot(true);
|
||||||
|
|
||||||
|
@ -165,11 +165,34 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QThread::Priority threadPriority(AbstractRunner::Priority priority)
|
||||||
|
{
|
||||||
|
switch (priority) {
|
||||||
|
case AbstractRunner::LowestPriority: {
|
||||||
|
return QThread::LowestPriority;
|
||||||
|
}
|
||||||
|
case AbstractRunner::LowPriority: {
|
||||||
|
return QThread::LowPriority;
|
||||||
|
}
|
||||||
|
case AbstractRunner::NormalPriority: {
|
||||||
|
return QThread::NormalPriority;
|
||||||
|
}
|
||||||
|
case AbstractRunner::HighPriority: {
|
||||||
|
return QThread::HighPriority;
|
||||||
|
}
|
||||||
|
case AbstractRunner::HighestPriority: {
|
||||||
|
return QThread::HighestPriority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kWarning() << "unhandled runner priority" << priority;
|
||||||
|
return QThread::InheritPriority;
|
||||||
|
}
|
||||||
|
|
||||||
RunnerManager *q;
|
RunnerManager *q;
|
||||||
RunnerContext context;
|
RunnerContext context;
|
||||||
QTimer matchChangeTimer;
|
QTimer matchChangeTimer;
|
||||||
QHash<QString, AbstractRunner*> runners;
|
QHash<QString, AbstractRunner*> runners;
|
||||||
QThreadPool *threadPool;
|
KThreadPool *threadPool;
|
||||||
QStringList allowedRunners;
|
QStringList allowedRunners;
|
||||||
bool prepped;
|
bool prepped;
|
||||||
bool allRunnersPrepped;
|
bool allRunnersPrepped;
|
||||||
|
@ -367,7 +390,7 @@ void RunnerManager::launchQuery(const QString &untrimmedTerm)
|
||||||
foreach (Plasma::AbstractRunner *runner, d->runners) {
|
foreach (Plasma::AbstractRunner *runner, d->runners) {
|
||||||
if ((runner->ignoredTypes() & d->context.type()) == 0) {
|
if ((runner->ignoredTypes() & d->context.type()) == 0) {
|
||||||
FindMatchesJob *job = new FindMatchesJob(runner, &d->context);
|
FindMatchesJob *job = new FindMatchesJob(runner, &d->context);
|
||||||
d->threadPool->start(job, static_cast<int>(runner->priority()));
|
d->threadPool->start(job, RunnerManagerPrivate::threadPriority(runner->priority()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue