Launch phonon player in a different thread? - qt

I have a Phonon.MediaObject that is connected to a web source through Phonon.AudioOutput. Therefore, when running play(), the main GUI freezes until the player starts playing (5 seconds at worst case).
This could be fixed by moving the player, or at least it's web fetching task. I've read online about moveToThread() function, but it doesn't seem to work.
I tried making a thread out of it, but without luck: http://pastebin.com/1iXdQD8Y (written in PyQt)
Any ideas?

This will require a bit more coding on your side.
I don't know python all that well, but from looking at your code I think that one mistake you are making is to assume that your PhononThread class is living in it's own thread, but it's actually living in thread in which it has been created.
I wouldn't even try to move objects like MediaObject between threads. One way to do it would be to create your own QObject descendant, then in it's constructor create all objects that you will need to play music. You will also need to add slots to your class to access every phonon function you will need to call from main thread. REMEMBER to create this object WITHOUT parent object.
Then you need to move it to newly created QThread and connect all signals/slots between threads.
I don't use python, but here is pseudo-C++ outline of how it should look like:
class MyPlayer: public QObject{
Q_OBJECT
public:
AudioOutput* ao;
MediaObject* mo;
MyPlayer() : QObject(0) { // note no parent QObject instance
ao = new AudioOutput();
... // Create and connect all objects
}
public slots:
void setCurrentSource ( const MediaSource & source ){
mo->setCurrentSource(source);
}
// And other methods that are not slots already.
};
Then in your application you do:
MyPlayer* mp = new MyPlayer();
QThread* th = new QThread();
connect(th, SIGNAL(finished()), mp, SLOT(deleteLater()));
connect( mainThreadObj, SIGNAL(setPlayerSource ( const MediaSource & ) ), mp, SLOT(setPlayerSource ( const MediaSource & ) ) );
... // and other signals; note that methods that are signals already can be conected witout wrappers:
connect( mainThreadObj, SIGNAL(playerPlay() ), mp->mo, SLOT(play()) );
mp->moveToThread(th);
For stopping your thread, just connect signal from your main thread to th's quit() slot, and emit it when needed.

Subclass QThread, reimplement run() with the stuff you want to happen in your thread, and then create an instance of your thread and call start() on it.
Just be careful about when you connect to things in your thread or from your thread, because you don't want to do a direct or auto connection, you want to do a queued connection in most cases.
This link shows two ways to use QThread, one as I just described, and it links to another producer consumer example using moveToThread().
what is the correct way to implement a QThread... (example please...)
Hope that helps.

Have you tried QtConcurrent::run? It runs function in a separate thread.
http://qt-project.org/doc/qt-4.8/qtconcurrentrun.html#run
or check it here https://stackoverflow.com/search?q=QtConcurrent%3A%3Arun

Related

Qt Communication betwen threads, app design

I'm working on an app which does some TCP communication, uses a database and has a GUI (pretty common). While experimenting with a database across the internet I've noticed slow responses of the GUI, which motivated using threads to handle the back end. I'm playing with this now and considering a full app re-design to adequately tackle the issue. So I'm imagining to separate GUI (a class derived from QMainWindow) and back end stuff (a domain class, derived from QObject). This domain class looks like (I say so because I'm clearly not an authority on patterns - always learning) a facade pattern. The idea is to construct both objects in the main function and then pass a pointer of DomainClass to MainWindow, i.e. MainWindow(DomainClass *domain).
Then comes the very point of this question. I'm imaging to construct many (not so much actually) objects in the Domain an make them communicate via signal/slots mechanics. Like the following:
QThread* threadDB = new QThread;
m_database = new Database;
m_database->moveToThread(threadDB);
threadDB->start();
QThread* threadTM = new QThread;
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnected);
m_tm->moveToThread(threadTM);
connect(threadTM, &QThread::started, m_tm, &TM::init);
threadTM->start();
But I'm getting the following:
QObject::connect: Cannot queue arguments of type 'QSqlDatabase'
(Make sure 'QSqlDatabase' is registered using qRegisterMetaType().)
I've noted that it works fine if I leave m_tm out of the thread. Like the following:
QThread* threadDB = new QThread;
m_database = new Database;
m_database->moveToThread(threadDB);
threadDB->start();
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnected);
Is this design reasonable? Which alternatives might be considered?
There are two issues. First, the runtime error tells you exactly what's wrong. You're trying to pass a database instance by value. Pass it by a pointer instead. The Qt metatype system knows how to handle such pointers.
class Database {
QSqlDatabase m_db;
...
public:
Q_SIGNAL void dbConnected(QSqlDatabase*);
...
};
Secondly, you can only use a QSqlDatabase instance from the thread it was created in (doc). So there's no point to passing it to an object living in a different thread. You should put TM in the same thread as that of the Database object, or you should have the Database object further encapsulate the database, exposing only a signal-slot interface that can then be used from any thread by using thread-safe queued calls.
Finally, you shouldn't use a "one thread per object" pattern. You must be able to give a reason, supported by measurements, that it is useful/helpful. A proliferation of threads is a bad thing - you should never have more than you have cores.
I'm making this an answer to have more room, but it might be tough as a comment considering #Kuba Ober answer.
To solve the second issue (pointed by #Kuba Ober) may I move DomainClass entirely to another thread? Coding the following on the constructor:
QThread* thread = new QThread;
this->moveToThread(thread);
connect(thread, &QThread::started, this, &DomainClass::init);
thread->start();
and coding the following on init():
m_database = new Database;
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnecte
In respect to #Kuba Ober comments...
Moved thread management job to domain's owner, so it does:
QThread *thread = new QThread;
domain->moveToThread(thread);
thread->start();
Changed Domain's constructor to do:
QTimer::singleShot(0, this, SLOT(init()));
Works pretty nice :)

QThread and QML Locking Up

I have a class, audio_engine_interface, and in main.cpp, I add it to the QML thing.
viewer.rootContext()->setContextProperty("engine", engine);
In audio_engine_interface, I have a audio_engine class, which is computationally intensive—it needs to run on its own thread.
void audio_engine_interface::play()
{
QThread thread;
thread.start();
engine->moveToThread(&thread);
engine->play(); // Will use 100% of CPU
}
However, when I do this, the whole QML thread locks up, meaning I can't pause (pretty important). Am I missing something?
EDIT:
This thread won't mess up anything or access objects from other places. However, it does have a pause function that will need to be called at some point. For what it's worth, the engine is doing pitch shifting.
This is a problem: -
Qthread thread;
Creating a QThread object like this is creating it on the stack. When the function ends, the object will go out of scope and delete the QThread object.
You need to dynamically allocate the object on the heap: -
QThread* thread = new QThread;
Then remember to delete the thread, or set it to delete itself: -
//Qt 5 connect syntax
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
You should also be aware of thread affinity (the thread which an object is running on). I suggest reading this article on how to use QThread properly.
You have so many problems.
when you move to thread your object must not have a parent
your thread object is local variable so it will day immediately when udio_engine_interface::play() end execution
you are invoking you engine->play(); method directly and this means that it will be executed in current thread.
moveToThread means that slots invked by signals connected using default 5th parameter (Qt::AutoConnection) will be queued in event loop of given thread.
The easiest way to fix it is use QtConcurrent:
void audio_engine_interface::play()
{
QtConcurrent::run(engine, &EngineClass::play);
}
Depending what your engine does you should make it thread safe (use mutex locks an so on), without details it is hard to tell, what exactly you should do.

How to call plain function from exec()?

I have 2 classes: one maintains some loop (at leas for 2-3 minutes; and is inherited from QObject) and another shows up a progress dialog (inherited from QDialog).
I want to start the loop as soon as the dialog is shown. My first solution was:
int DialogClass::exec()
{
QTimer::singleShot(0, LoopClassPointer, SLOT(start()));
return __super::exec();
}
There is a problem with throwing exceptions from slots. so I considered a possibility to make public slot start() just a public function. But now I don't know how to make it works well. Things like this:
int DialogClass::exec()
{
LoopClassPointer->start();
QApplication::processEvents();
return __super::exec();
}
don't help. The dialog doesn't appears.
Is there a common approach to this kind of situations?
some details, according to questions:
I have to work with system with its own styles, so we have a common approach in creating any dialogs: to inherit them from stytle class, which is inherited from QDialog.
my 'LoopClassPointer' is an exported class from separate dll (there is no UI support in it).
I have a 'start' button in main app, which connected with a slot, which creates progress dialog and 'LoopClassPointer'. at the moment I send 'LoopClassPointer' instance in the dialog and don't whant to make significant changes in the architecture.
Take a look at QtDemo->Concurrent Programming->Run function
e.g. in Qt 4.8: http://qt-project.org/doc/qt-4.8/qtconcurrent-runfunction.html
In this situation, I recommend you separate the logic of the loop from the dialog. Gui elements should always be kept separate.
It's great that your worker class is derived from QObject because that means you can start it running on a separate thread: -
QThread* m_pWorkerThread = new QThread;
Worker* m_pWorkerObject = new Worker; // assuming this object runs the loop mentioned
// Qt 5 connect syntax
connect(m_pWorkerThread, &QThread::started, m_pWorkerObject, &WorkerObject::start);
connect(m_pWorkerThread, &QThread::finished, m_pWorkerThread, &QThread::deleteThis);
m_pWorkerObject->moveToThread(m_pWorkerThread);
m_pWorkerThread->start();
If you're not familiar with using QThread, then start by reading this.
The only other thing you require is to periodically send signals from your worker object with progress of its work and connect that to a slot in the dialog, which updates its display of the progress.

Controlling a QObject working in another thread, bypassing event queue, freezes the GUI

I'm working with QThread and slots/signals mechanism; I know there's a lot of threads about this on the Web in general and here at SO in particular, but I still could not find a solution. Anyway, here is the context.
The piece of code I am trying to come up with is aimed at controlling though the GUI an eventually long process, hence the use of a QThread.
I have a window with two buttons, start and stop. My Window also has a QThread and Task, where the latter inherits from a QObject. I do want to be able to stop my task while it is running, and to prevent starting it again if start is clicked while it is already running.
Here is an excerpt of Task (which fakes the long process):
class Task: public QObject
{
public:
Task(): QObject(), stop_(true) {}
private slots:
void startTask()
{
stop_ = false;
run();
}
void stopTask()
{
stop_ = true;
}
void run() const
{
while ( ! stop_)
{
sleep(1);
}
}
bool stop_;
};
I made two connections between the buttons and the task in the constructor of my Window:
class Window: public QWidget
{
public:
Window()
{
// Instantiate buttons and put them in a layout.
// ...
connect(buttonStart_, SIGNAL(clicked()), &task_, SLOT(startTask()));
connect(buttonStop_, SIGNAL(clicked()), &task_, SLOT(stopTask()),
Qt::DirectConnection);
task_.moveToThread(&thread);
thread_.start();
}
private:
QPushButton buttonStart_;
QPushButton buttonStop_;
QThread thread_;
Task task_;
};
I used Qt::DirectConnection in the second connect() in order to "force" processing of my signal requesting to stop the task, as (as I understand) task_ needs to return from its work before processing events further (if I use the default connection, all my clicks are processed after my task is "done").
Here, the Qt::DirectConnection "bypasses" the event queue, and that way I can stop my task. But to be honest I don't know if that is the proper way to do it, or if it is a workaround (thus possibly the root of my problem).
Anyway, this works OK that way, but when I start playing with my buttons, the GUI gets eventually frozen, and that's my problem!
Any help is welcome; thanks for your time!
Using a DirectConnection means that the slots will be executed in the UI thread (while your task thread is still running). This is not what you want. The way to handle this is to use an event loop in your thread, by running with QThread::exec().
In order for your thread to be able to respond as you want, you will need to ensure that the thread is able to process incoming events. There are a few ways to deal with this. One would be to call QCoreApplication::processEvents() occasionally while your task is running. Another is to use a QTimer connected to a slot which performs some processing. The important thing is to make sure that the event loop in your thread can run.
The first thing you need to understand is which thread your signal/slot connections are being executed in.
The default behavior in this particular case is to use a Qt::QueuedConnection, which will put your signal event onto the receiving thread's event queue. In the case of a Qt::DirectConnection, the slot is executed in the thread of the object that emitted the signal.
Using a Qt::DirectConnection would only be safe in this instance if you put a mutex around your stop_ variable to prevent both threads from accessing it at the same time.

Ways to create a QDialog outside the main thread

I am trying to create a client application in QT which requires both threads for processing and a variable amount of window instances. But I am having a hard time trying to figure out how to create a new window inside one of the processing thread. I understand that all ui elements must be created in the same thread as the QApplication class, but I need to be able to instantiate, or at least have a reference to a QDialog in another thread.
Communicating between the thread and QDialog can be done using signals, I am not worried about this, but actually creating the window is another matter. I could use signals to tell the main thread to create an instance to the window, and then retrieve the pointer to it somehow, but to me that seems a bit to complicated and ugly. Is there a better way to accomplish such a task? To create a QDialog outside the main thread were the QApplication class exists?
Edit : I have tried the Q_INVOKABLE method but it does not work across threads. I have created a view factory class which can create a QDialog of a type I specify and returns a pointer to it. This class has been instantiated in the main GUI thread and a reference to this class is sent to any worker threads. The problem is that, when a thread invokes the create method from the factory using Qt::BlockingQueuedConnection, the invoke method fails. If I change it to Qt::DirectConnection, the invoke method calls the right create method but in the current thread as the worker thread.
My main function looks like this :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ViewFactory vFactory;
vFactory.registerCreator(Util::W_CONNECT, new ConnectWindow::ConnectCreator());
ClientApp app;
if(!app.Initialize(&vFactory))
return 0;
app.start();
a.exec();
.............................
}
And my run function from the ClientApp thread looks something like this :
void ClientApp::run()
{
QDialog * tmp = NULL;
QMetaObject::invokeMethod(this->_vFactory, "create", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QDialog*, tmp), Q_ARG(int, 0));
}
Like I said, the invokeMothod will not fail if I change the connection type to Qt::DirectConnection, so the params are not the problem, but rather calling the method across a separate worker thread.
You can only do Gui stuff in the gui thread. The obvious solution is for the worker thread to send a message to the gui thread = a signal in Qt terms.
If a worker thread needs to ask a question it should send a message to the gui thread and then block until it gets a signal back.
AFAIK, signals (or just a dynamically callable method, using Q_INVOKABLE) or an event is the way to go.
Note that, using QMetaObject::invokeMethod() (with Qt::BlockedConnection), you can call a function safely across threads and get a return value back without too much coding.
It seems like QObject::moveToThread can solve this problem. This function moves event processing loop to another thread.
Example from Qt documentation:
myObject->moveToThread(QApplication::instance()->thread());

Resources