mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-20 14:33:19 +01:00
Add ConcurrentRun functions, and us one of them in gstenginepipeline with gstenginepipeline's own threadpool.
So now we can (finally!) play/pause/stop music while fingerprinting lot of songs or whatever else
This commit is contained in:
parent
fbda1f9489
commit
76b98000fe
134
ext/libclementine-common/core/concurrentrun.h
Normal file
134
ext/libclementine-common/core/concurrentrun.h
Normal file
@ -0,0 +1,134 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2012, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef THREADFUNCTION_H
|
||||
#define THREADFUNCTION_H
|
||||
|
||||
#include <tr1/functional>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
|
||||
/*
|
||||
The aim of ThreadFunctor classes and ConcurrentRun::Run() functions is to
|
||||
complete QtConcurrentRun, which lack support of using a particular
|
||||
QThreadPool, as it always uses QThreadPool::globalInstance().
|
||||
|
||||
This is problematic when we do not want to share the same thread pool over
|
||||
all the application, but want to keep the convenient QtConcurrent::run()
|
||||
functor syntax: time critical changes are performed in their own pool, which
|
||||
is not empty by other actions, like when using QtConcurrentRun::run()
|
||||
|
||||
ThreadFunctor classes are used to store a functor and its arguments, and
|
||||
Run() functions are used for convenience: to directly create a new
|
||||
ThreadFunctor object and start it.
|
||||
|
||||
Currently, only functions with two arguments and a return value are
|
||||
supported, but other might be added easily for X arguments by defining a new
|
||||
ThreadFunctorBasX class, and add new Run() function.
|
||||
*/
|
||||
|
||||
template<typename ReturnType>
|
||||
class ThreadFunctorBase : public QFutureInterface<ReturnType>, public QRunnable {
|
||||
public:
|
||||
ThreadFunctorBase() {}
|
||||
|
||||
QFuture<ReturnType> Start(QThreadPool* thread_pool) {
|
||||
this->setRunnable(this);
|
||||
this->reportStarted();
|
||||
Q_ASSERT(thread_pool);
|
||||
QFuture<ReturnType> future = this->future();
|
||||
thread_pool->start(this, 0 /* priority: currently we do not support
|
||||
changing the priority. Might be added later
|
||||
if needed */);
|
||||
return future;
|
||||
}
|
||||
|
||||
virtual void run() = 0;
|
||||
|
||||
void End() {
|
||||
this->reportResult(result_);
|
||||
this->reportFinished();
|
||||
}
|
||||
|
||||
protected:
|
||||
ReturnType result_;
|
||||
};
|
||||
|
||||
template<typename ReturnType, typename Arg>
|
||||
class ThreadFunctor1 : public ThreadFunctorBase<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor1(std::tr1::function<ReturnType (Arg)> function,
|
||||
const Arg& arg)
|
||||
: function_(function),
|
||||
arg_(arg)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
this->result_ = function_(arg_);
|
||||
ThreadFunctorBase<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<ReturnType (Arg)> function_;
|
||||
Arg arg_;
|
||||
};
|
||||
|
||||
template<typename ReturnType, typename Arg1, typename Arg2>
|
||||
class ThreadFunctor2 : public ThreadFunctorBase<ReturnType> {
|
||||
public:
|
||||
ThreadFunctor2(std::tr1::function<ReturnType (Arg1, Arg2)> function,
|
||||
const Arg1& arg1, const Arg2& arg2)
|
||||
: function_(function),
|
||||
arg1_(arg1),
|
||||
arg2_(arg2)
|
||||
{ }
|
||||
|
||||
void run() {
|
||||
this->result_ = function_(arg1_, arg2_);
|
||||
ThreadFunctorBase<ReturnType>::End();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tr1::function<ReturnType (Arg1, Arg2)> function_;
|
||||
Arg1 arg1_;
|
||||
Arg2 arg2_;
|
||||
};
|
||||
|
||||
namespace ConcurrentRun {
|
||||
|
||||
template<typename ReturnType, typename Arg>
|
||||
QFuture<ReturnType> Run(
|
||||
QThreadPool* threadpool,
|
||||
std::tr1::function<ReturnType (Arg)> function,
|
||||
const Arg& arg) {
|
||||
|
||||
return (new ThreadFunctor1<ReturnType, Arg>(function, arg))->Start(threadpool);
|
||||
}
|
||||
|
||||
template<typename ReturnType, typename Arg1, typename Arg2>
|
||||
QFuture<ReturnType> Run(
|
||||
QThreadPool* threadpool,
|
||||
std::tr1::function<ReturnType (Arg1, Arg2)> function,
|
||||
const Arg1& arg1, const Arg2& arg2) {
|
||||
|
||||
return (new ThreadFunctor2<ReturnType, Arg1, Arg2>(function, arg1, arg2))->Start(threadpool);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // THREADFUNCTION_H
|
30
tests/concurrentrun_test.cpp
Normal file
30
tests/concurrentrun_test.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QEventLoop>
|
||||
#include <QFutureWatcher>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include "core/concurrentrun.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
int max(int i, int j) {
|
||||
return (i > j ? i : j);
|
||||
}
|
||||
|
||||
TEST(ConcurrentRunTest, ConcurrentRunStartAndWait) {
|
||||
int i = 10;
|
||||
int j = 42;
|
||||
QThreadPool threadpool;
|
||||
QFuture<int> future = ConcurrentRun::Run<int, int, int>(&threadpool, &max, i, j);
|
||||
QFutureWatcher<int> watcher;
|
||||
watcher.setFuture(future);
|
||||
QEventLoop loop;
|
||||
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
EXPECT_EQ(42, watcher.result());
|
||||
}
|
||||
|
||||
// TODO: add some more complex test cases? (e.g. with several CPU-consuming
|
||||
// tasks launched in parallel, with/without threadpool's threads numbers
|
||||
// decreased, etc.)
|
Loading…
Reference in New Issue
Block a user