This repository has been archived by the owner on Sep 4, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[mt] Generic actor implementation around QThread
Actor creates QObject inside QThread and allows to post/send events to it, protecting it from incorrect direct access. Signed-off-by: Denis Zalevskiy <denis.zalevskiy@jolla.com>
- Loading branch information
Denis Zalevskiy
committed
Nov 6, 2014
1 parent
29a659f
commit 28e8e37
Showing
8 changed files
with
355 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
#ifndef _QTAROUND_MT_HPP_ | ||
#define _QTAROUND_MT_HPP_ | ||
/** | ||
* @file mt.hpp | ||
* @brief Concurrency support | ||
* @copyright (C) 2014 Jolla Ltd. | ||
* @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html | ||
*/ | ||
|
||
#include <qtaround/util.hpp> | ||
#include <QThread> | ||
#include <QCoreApplication> | ||
|
||
namespace qtaround { namespace mt { | ||
|
||
class AnyActor; | ||
typedef std::shared_ptr<AnyActor> AnyActorHandle; | ||
|
||
class ActorContext : public QObject | ||
{ | ||
Q_OBJECT | ||
public: | ||
typedef std::function<UNIQUE_PTR(QObject) ()> ctor_type; | ||
typedef std::function<void (AnyActorHandle)>callback_type; | ||
ActorContext(AnyActorHandle actor, ctor_type ctor, callback_type cb) | ||
: actor_(actor), ctor_(ctor), notify_(cb) | ||
{} | ||
|
||
AnyActorHandle actor_; | ||
ctor_type ctor_; | ||
callback_type notify_; | ||
}; | ||
|
||
class AnyActor : public QThread | ||
{ | ||
Q_OBJECT | ||
protected: | ||
virtual ~AnyActor(); | ||
|
||
void run() Q_DECL_OVERRIDE; | ||
|
||
public: | ||
AnyActor(QObject *parent) : QThread(parent) {} | ||
|
||
AnyActor(AnyActor const&) = delete; | ||
AnyActor& operator = (AnyActor const&) = delete; | ||
|
||
static void create(ActorContext::ctor_type | ||
, ActorContext::callback_type | ||
, QObject *parent = nullptr); | ||
|
||
static AnyActorHandle createSync | ||
(ActorContext::ctor_type, QObject *parent = nullptr); | ||
|
||
bool postEvent(QEvent *); | ||
bool sendEvent(QEvent *); | ||
|
||
private: | ||
std::shared_ptr<QObject> obj_; | ||
}; | ||
|
||
template <typename T> void startActor | ||
(std::function<UNIQUE_PTR(T) ()> ctor | ||
, ActorContext::callback_type cb, QObject *parent = nullptr | ||
, typename std::enable_if<std::is_convertible<T*, QObject*>::value>::type* = 0) | ||
{ | ||
auto qobj_ctor = [ctor]() { | ||
return static_cast_qobject_unique<QObject>(ctor()); | ||
}; | ||
AnyActor::create(qobj_ctor, cb, parent); | ||
} | ||
|
||
template <typename T> AnyActorHandle startActorSync | ||
(std::function<UNIQUE_PTR(T) ()> ctor, QObject *parent = nullptr | ||
, typename std::enable_if<std::is_convertible<T*, QObject*>::value>::type* = 0) | ||
{ | ||
auto qobj_ctor = [ctor]() { | ||
return static_cast_qobject_unique<QObject>(ctor()); | ||
}; | ||
return AnyActor::createSync(qobj_ctor, parent); | ||
} | ||
|
||
}} | ||
|
||
#endif // _QTAROUND_MT_HPP_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/** | ||
* @file mt.cpp | ||
* @brief Concurrency support | ||
* @copyright (C) 2014 Jolla Ltd. | ||
* @par License: LGPL 2.1 http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html | ||
*/ | ||
|
||
#include <qtaround/debug.hpp> | ||
#include <qtaround/mt.hpp> | ||
#include <mutex> | ||
#include <condition_variable> | ||
|
||
namespace qtaround { namespace mt { | ||
|
||
AnyActor::~AnyActor() | ||
{ | ||
auto app = QCoreApplication::instance(); | ||
if (app) { | ||
if (isRunning()) | ||
quit(); | ||
if (QThread::currentThread() != this) | ||
if (!wait(10000)) | ||
debug::warning("Timeout: no quit from thread!"); | ||
} | ||
if (obj_ && this != QThread::currentThread()) | ||
debug::warning("Managed object is not deleted in a right thread Current:" | ||
, QThread::currentThread(), ", Need:", this); | ||
} | ||
|
||
void AnyActor::run() | ||
{ | ||
auto ctx = std::static_pointer_cast<ActorContext>(std::move(obj_)); | ||
obj_ = ctx->ctor_(); | ||
ctx->notify_(std::move(ctx->actor_)); | ||
exec(); | ||
obj_.reset(); | ||
} | ||
|
||
bool AnyActor::postEvent(QEvent *e) | ||
{ | ||
auto obj = obj_; | ||
|
||
if (obj) { | ||
QCoreApplication::postEvent(obj.get(), e); | ||
return true; | ||
} else { | ||
if (e) delete e; | ||
return false; | ||
} | ||
} | ||
|
||
bool AnyActor::sendEvent(QEvent *e) | ||
{ | ||
auto obj = obj_; | ||
if (obj) { | ||
return QCoreApplication::sendEvent(obj.get(), e); | ||
} else { | ||
if (e) delete e; | ||
return false; | ||
} | ||
} | ||
|
||
void AnyActor::create | ||
(ActorContext::ctor_type ctor, ActorContext::callback_type cb | ||
, QObject *parent) | ||
{ | ||
auto self = make_qobject_shared<AnyActor>(parent); | ||
auto ctx = make_qobject_unique<ActorContext> | ||
(self, std::move(ctor), std::move(cb)); | ||
self->obj_ = qobject_shared_cast(std::move(ctx)); | ||
self->start(); | ||
} | ||
|
||
AnyActorHandle AnyActor::createSync | ||
(ActorContext::ctor_type ctor, QObject *parent) | ||
{ | ||
std::mutex mutex; | ||
std::condition_variable cond; | ||
AnyActorHandle result; | ||
std::unique_lock<std::mutex> l(mutex); | ||
create(ctor, [&](mt::AnyActorHandle p) { | ||
std::unique_lock<std::mutex> l(mutex); | ||
result = p; | ||
cond.notify_all(); | ||
}, parent); | ||
cond.wait(l, [&result]() { return !!result; }); | ||
return result; | ||
} | ||
|
||
}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.