Mam obiekt na żywo zaimplementowany w następujący sposób. Służy do wykonywania długich zadań w tle. Główny wątek wywołuje zadania, wysyłając sygnał do publicznych gniazd (to jest doTask). Oto obnażony przykład (nie testowany).Wywołać metodę gniazda bez połączenia?
class MyTask : public QObject
{
Q_OBJECT
public:
MyTask();
~MyTask();
public slots:
void doTask(int param);
private slots:
void stated();
signals:
void taskCompleted(int result);
private:
QThread m_thread;
};
MyTask::MyTask()
{
moveToThread(&m_thread);
connect(&m_thread, SIGNAL(started()), this, SLOT(started()));
m_thread.start();
}
MyTask::~MyTask()
{
// Gracefull thread termination (queued in exec loop)
if(m_thread.isRunning())
{
m_thread.quit();
m_thread.wait();
}
}
void MyTask::started()
{
// initialize live object
}
void MyTask::doTask(int param)
{
sleep(10);
emit taskCompleted(param*2);
}
Ten (powinien) działać zgodnie z oczekiwaniami, dopóki doTask() jest wywoływany przez sygnał. Ale jeśli główny wątek wywoła metodę doTask() bezpośrednio, zostanie ona wykonana przez główny wątek. W przypadku niektórych zadań chcę wymusić wykonanie przez wątek bieżącego obiektu, nawet jeśli metoda jest wywoływana bezpośrednio.
Mogłem dodać kod przed funkcją doTask(), aby sprawdzić, czy bieżący wątek to m_thread, w którym to przypadku metoda jest wykonywana. Jeśli nie, chciałbym, aby doTask() wysyłał sygnał do "this", tak aby wywołanie metody doTask() było umieszczane w kolejce w pętli exec m_thread i wykonywane przez nią tak szybko, jak to możliwe.
Jak mogę to zrobić?
EDIT: W oparciu o proponowaną odpowiedź, oto nowy kod. Metoda doTask teraz deleguje wykonanie przez wątek live objet, nawet jeśli jest wywoływana bezpośrednio przez główny wątek. Wywoływany przez sygnał nadal działa zgodnie z oczekiwaniami.
class MyTask : public QObject
{
Q_OBJECT
public:
explicit MyTask(QObject *parent = 0);
~MyTask();
public slots:
void doTask(int param);
private slots:
void doTaskImpl(int param);
signals:
void taskCompleted(int result);
private:
QThread m_thread;
};
MyTask::MyTask(QObject *parent) : QObject(parent)
{
moveToThread(&m_thread);
m_thread.start();
}
MyTask::~MyTask()
{
// Gracefull thread termination (queued in exec loop)
if(m_thread.isRunning())
{
m_thread.quit();
m_thread.wait();
}
}
void MyTask::doTask(int param)
{
QMetaObject::invokeMethod(this, "doTaskImpl", Q_ARG(int, param));
}
void MyTask::doTaskImpl(int param)
{
// Do the live oject's asynchronous task
sleep(10);
emit taskCompleted(param*2);
}
Jest to najprostsza implementacja, jaką mogłem znaleźć, aby obsługiwać metody asynchroniczne w osobnym wątku. Wywołania metod doTask() będą kolejkowane i przetwarzane zaraz po uruchomieniu wątku. Wywoływany z wątku obiektu, zostanie wykonany natychmiast (nie w kolejce).
Należy zauważyć, że sygnał uruchomienia() jest emitowany tylko po uruchomieniu wątku. Oznacza to, że wywołanie metody doTask() w kolejce przed uruchomieniem wątku zostanie wykonane przed wywołaniem wywołania metody begin(). Z tego powodu usunąłem go z początkowej implementacji. Inicjowanie obiektów powinno zatem być korzystnie wykonywane w konstruktorze.
widzę problemu w tym miejscu: docs powiedzieć, że nie można przenieść obiekt do innego wątku czy to ma rodzica. Czy Twój kod działa, gdy MyTask jest tworzony z rodzicem? – andref
Podobne pytanie zostało już udzielone w [QT + Jak wywołać slot z niestandardowego kodu C++ działającego w innym wątku] (http: // stackoverflow.com/questions/1144240/qt-how-to-call-slot-from-custom-c-code-running-in-a-different-thread). – Trilarion