created two thread from within main thread - qthread - qt

I have created two threads from within a main thread in linux but how to create them in QT?
My GUI has two buttons start & stop.
I want that when start button is pressed then a main thread starts & it starts two threads TX & RX.
When stop button is pressed then tx thread stops, then receive thread stops & then main thread stops.
I need to create two threads (TX/RX) from a main thread.
Please suggest how to complete my code.
Do I have to create seperate object for tx/rx thread & then move these objects to respective Qthread m_preceiveThread, m_pwriteThread?
Also which point should tx & rx thread be created(should i create them in constructor of main thread object) ?
What logic should be used to stop the threads when button is pressed (Mostly we use to set a flag which takes control out of the thread work function)?
When dowork() function ends, will the thread terminate?
I have created two Qthread QThread m_preceiveThread; & QThread m_pwriteThread; inside the deviceThreadObject object, is it the right place to have the threads which i will be starting from my main thread ?
6.Also before applying movetothread function to my main thread. Do I will have to prepare the tx & rx thread in the constructor of main thread object deviceThreadObject m_deviceThreadObject; or in the slot() which is triggred when thread is started.
Create thread:
QThread m_deviceThread;
deviceThreadObject m_deviceThreadObject;
connect(&m_deviceThread,SIGNAL(started()),m_deviceThreadObject,SLOT(dowork()));
m_deviceThreadObject.moveToThread(&m_deviceThread);
Tx/Rx Thread object:
/// forward declarations
class deviceThreadObject;
// transmit & receive thread object
class txRxThreadObject : public QObject
{
Q_OBJECT
public:
explicit txRxThreadObject(QObject *parent = 0);
deviceThreadObject *m_pMainThreadObj;
/* Termination control thread*/
bool m_bQuitRx;
bool m_bQuitTx;
signals:
public slots:
void dowork_tx();
void dowork_rx();
};
Main device thread object:
class deviceThreadObject : public QObject
{
Q_OBJECT
public:
explicit deviceThreadObject(QObject *parent = 0);
QThread m_preceiveThread;
QThread m_pwriteThread;
bool m_bQuit;
/// Pointer to QStandardItemModel to be used inside - canTableView
QStandardItemModel *modeltable;
/// pointer to the txRxThreadObject object
class txRxThreadObject *m_ptxRxThreadObject;
/// setup function for device thread
void dosetup(QThread &devThread);
signals:
public slots:
void dowork()
{
for(int i=0; i<100; i++)
{
qDebug() << "hello";
}
}
};

Related

Qt: How to avoid deadlock when multiple queued signals invoke same slot

In following code I meet deadlock in someOperation:
class A : public QObject {
Q_OBJECT
public:
explicit A(QObject* parent) : QObject(parent), data(0) {}
public slots:
void slot1() {
someOperation();
}
void slot2() {
someOperation();
}
void slot3() {
someOperation();
}
private:
void someOperation() {
QMutexLocker lk(&mutex);
data++;
QMessageBox::warning(NULL, "warning", "warning");
data--;
assert(data == 0);
}
int data;
QMutex mutex; //protect data
};
class Worker: public QThread {
Q_OBJECT
public:
explicit Worker(QObject* parent) : QThread(parent) {}
protected:
virtual void run() {
// some complicated data processing
emit signal1();
// other complicated data processing
emit signal2();
// much complicated data processing
emit signal3();
qDebug() << "end run";
}
signals:
void signal1();
void signal2();
void signal3();
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
A* a = new A(&app);
Worker* w = new Worker(a);
QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);
w->start();
return app.exec();
}
There is a thread that will emit three signals, all of them queued connected to an instance of class A, and all class A' slots will call to someOperation, and someOperation is protected by mutex and it will popup a message box.
Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
It seems slot2 is invoked when slot1's message box still doing modal, in main thread, but at that time slot1 has lock mutex, so deadlock.
How to change the code to avoid deadlock?
Update:(Jan.17, 2019)
What I want archive is that: slot2 not be execute before slot1 finished.
What should be kept are:
worker is a background thread to process data, cost long time; so, whatever, the three signals will emit from other thread.
worker should not blocked by emitting signals.
slots should execute in main thread, because they will update GUI.
someOperation is not reentrant.
The requirement that "someOperation is not reentrant" is an odd one. What should happen if reentrancy is attempted? Given that someOperation can only be called from the main thread I can only see two options...
Block completely with mutex/barrier etc. as you have tried.
Block based on a recursion level counter and spin the event loop until that counter decrements to zero.
1) Will block the thread's event loop completely preventing the current message dialog from functioning correctly.
2) Will allow all message dialogs simultaneously rather then serialising them.
Rather than trying to make someOperation non-reentrant I think you need to make sure you use in a way that won't result in reentrancy.
One option might be to make use of a separate QObject derived class instance on its own QThread. Consider the following...
class signal_serialiser: public QObject {
Q_OBJECT;
signals:
void signal1();
void signal2();
void signal3();
};
If an instance of signal_serialiser is moved to its own thread it can act as a queue to buffer and forward the various signals if suitable connection types are used. In your code you currently have...
QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);
Change that to...
signal_serialiser signal_serialiser;
QObject::connect(w, SIGNAL(signal1()), &signal_serialiser, SIGNAL(signal1()));
QObject::connect(w, SIGNAL(signal2()), &signal_serialiser, SIGNAL(signal2()));
QObject::connect(w, SIGNAL(signal3()), &signal_serialiser, SIGNAL(signal3()));
/*
* Note the use of Qt::BlockingQueuedConnection for the
* signal_serialiser --> A connections.
*/
QObject::connect(&signal_serialiser, SIGNAL(signal1()), a, SLOT(slot1()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal2()), a, SLOT(slot2()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal3()), a, SLOT(slot3()), Qt::BlockingQueuedConnection);
QThread signal_serialiser_thread;
signal_serialiser.moveToThread(&signal_serialiser_thread);
signal_serialiser_thread.start();
I've only done basic testing but it appears to give the desired behaviour.
That's because your function void someOperation() is not reentrant.
The static functions of QMessageBox span their own event loop, which calls QCoreApplication::processEvents() repeatedly:
Execution of the first invocation of someOperation() gets stuck at QMessageBox::warning(...).
In there, exec() calls processEvents(), 3. which sees the second signal
and invokes someOperation() again
where trying to re-lock mutex fails.
How to resolve this depends on what you want to achieve...
About your general approach to QThread: You're doing it wrong.
(That link gives a good start into the topic, but not a complete solution.)
You create and start a background thread. But that thread will only emit the three signals and then finish.
The slots will be called inside the main (GUI) event loop, because that's the thread affinity of your A *a.
To make the slots be executed in the background, you need to:
create your A instance without a parent: A *a = new A();
create your Worker instance with the app as parent: Worker *w = new Worker(&app); (or with nothing, at least not with a)
change the thread affinity of your A instance: a->moveToThread(Worker);
don't override Worker::run(), or if you really want to (see point 5), call the base implementation: QThread::run();
emit the signals from main (you can emit them from run(), but that's not necessary).

QObject: Cannot create children for a parent that is in a different thread & QProcess [duplicate]

I am using Qt 4.6.0 (32 bit) under Windows 7 Ultimate. Consider the following QThread:
Interface
class ResultThread : public QThread
{
Q_OBJECT
QString _post_data;
QNetworkAccessManager _net_acc_mgr;
signals:
void onFinished(QNetworkReply* net_reply);
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
ResultThread();
void run();
void setPostData(const QString& post_data);
};
Implementation
ResultThread::ResultThread() : _net_acc_mgr(this)
{
connect(&_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void ResultThread::onReplyFinished(QNetworkReply* net_reply)
{
emit onFinished(net_reply);
}
void ResultThread::setPostData(const QString& post_data)
{
_post_data = post_data;
}
void ResultThread::run()
{
_net_acc_mgr.post(QNetworkRequest(QUrl("http://[omitted]")),
QByteArray(_post_data.toStdString().c_str()));
}
Whenever _net_acc_mgr.post() is executed in ResultThread::run(), I got the following Application Output in Qt Creator:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x22fe58), parent's thread is QThread(0x9284190), current thread is ResultThread(0x22fe48)
What does this mean? How to solve it?
The run() member function is executed in a different thread, rather than the thread where QNetworkRequestManager object was created.
This kind of different-thread problems happen all the time with Qt when you use multiple threads. The canonical way to solve this problem is to use signals and slots.
Create a slot in the object where QNetworkRequestManager belongs to, create a signal in ResultThread and connect both of the somewhere, the constructor of ResultThread would be a good place.
The code which is currently in ResultThread::run() goes to the new slot, and is replaced by a emit(yourSignal()). If necessary send a pointer to your ResultThread as a parameter with your emit function to gain access to member functions/variables.
I received this error message when I forgot to set the QNetworkRequestManager's parent.
nam = new QNetworkAccessManager(this);

Why does my asynchronous QProgressBar render black?

I want a QProgressBar to show in a modal dialog and update asynchronously as another thread does work.
struct ProgressThread : public QThread
{
QDialog m_dialog;
QProgressBar * m_bar;
ProgressThread (QWidget * parent, int range)
: m_dialog (parent)
, m_bar (new QProgressBar ())
{
auto l = new QGridLayout (& m_dialog);
l -> addWidget (m_bar, 0, 0);
m_bar -> setRange (0, range);
}
void run () override
{
m_dialog .exec ();
}
};
ProgressThread thread (this, range);
thread .start ();
int num = 0;
for (each job)
{
do_some_work ();
thread .m_bar -> setValue (++ num);
}
thread .m_dialog .accept ();
thread .wait (1000);
thread .quit ();
It basically works except the progress bar renders as a black block. Why is this happening?
This is a design problem. Neither Qt nor most of other UI frameworks designed to run multiple threads for UI though this innovative approach may take place. Most of UI classes just expect to be running on same main thread. Qt can never guarantee that it works the way you are attempting: running the dialog exec() on a worker thread.
How to convert the source code you have to Qt way? Your source code encapsulates QDialog and QProgressBar immediately in thread instance which is maybe not incorrect yet until you do moveToThread(uiObject). But still, it shows the wrong design. You can just follow normal pattern for the worker thread interacting with UI:
// make sure to place it in the header file
class ProgressThread : public QDialog
{
Q_OBJECT
public:
// if you ever need to access that from outside
// QProgressBar* bar() {return m_bar;}
public slots:
void moveProgress(int);
private:
QProgressBar* m_bar;
};
class ProgressThread : public QThread
{
Q_OBJECT
public:
// add methods
signals:
moveProgress(int);
};
You need to connect the slot to signal:
// for interthread communication a queued connection will be automatical
// figure out how to get the pointer to that dialog class (dialogPtr)
QObject::connect(&thread, SIGNAL(moveProgress(int)), dialogPtr(), SLOT(moveProgress(int));
And from the thread code you emit the signal to advance the progress bar on UI thread:
emit moveProgress(value);
The similar question/answers: QProgressBar not showing progress?
And make sure that UI thread starts from the application main() function!

Is there a guarantee that no signals are delivered from a different thread after QObject::disconnect()?

I am not thinking of the problem that queued signals are still delivered in the receiving thread after disconnect(), instead:
Consider the case that a Sender object is generating signals in thread 1 and there is a Receiver object in thread 2 which has a slot that is connected to Sender's signal via a Qt::DirectConnection.
Now, in Receiver::~Receiver(), I need to make sure that no signals are still delivered while the object is already (maybe partially) destructed. Because the connection is direct, the slot could be invoked in thread 1 at any time and could in particular happen between destruction of Receiver's specific attributes and destruction of the base QObject which will also disconnect signals. So, my question boils down to:
Is it enough to disconnect Sender and Receiver objects in thread 2 before destruction of the Receiver object, or do I need to make sure that no signals are emitted in thread 1 during the disconnect() call?
I am thinking of the case where thread 1 is in the middle of emitting the signal, e.g. right at the top of executing the receiving slot and right at that moment, in thread 2, the disconnect() call is done. If disconnect() waits (via a mutex) for thread 1 to finish delivering the signal before doing the disconnect and blocking further signal deliveries, everything would be fine but I am not sure that's the case.
Yes disconnect() and connect() are using mutexes for protection.
These are the first lines of the disconnect() function:
bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
DisconnectType disconnectType)
{
if (!sender)
return false;
QObject *s = const_cast<QObject *>(sender);
QMutex *senderMutex = signalSlotLock(sender);
QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0;
QOrderedMutexLocker locker(senderMutex, receiverMutex);
And here are the first lines of the connect() function:
bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index, int type, int *types)
{
QObject *s = const_cast<QObject *>(sender);
QObject *r = const_cast<QObject *>(receiver);
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
If you check the QObject documentation you can see that :
Note: All functions in this class are reentrant, but connect(),
connect(), disconnect(), and disconnect() are also thread-safe.
EDIT
When a signal is emitted the QMetaObject::activate function is called which locks the sender's object mutex:
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv)
{
...
QMutexLocker locker(signalSlotLock(sender));

QThread never runs/finishes before it can be used?

I have created a custom QObject class called EncodeThread, which looks as follows:
class EncodeThread : public QObject {
Q_OBJECT
public:
void set(SWSL::Video* v, QStringList f, QDir vDir);
void run();
public slots:
void encode();
signals:
void encodeProgress(int i);
private:
SWSL::Video* video;
QStringList files;
QDir videoDir;
};
As may be obvious, this class is used for encoding a video using an external library. Encode() contains the actual encoding routine, run() is a function I added while troubleshooting, though it's obviously non-functional:
void EncodeThread::run() {
if (currentThread() != this) {
// caller is in different thread.
QMetaObject::invokeMethod(this, "encode", Qt::QueuedConnection);
}
else {
encode();
}
}
The problem is when I use a QThread and the moveToThread() function on the EncodeThread instance, namely that nothing seems to happen. No data is written, and the instance never emits the signal which should save the encoded file to disk.
encThread.set(video, files, videoDir);
connect(&encThread, SIGNAL(encodeProgress(int)), cookVideoProgress, SLOT(setValue(int)));
connect(&encThread, SIGNAL(finished()), this, SLOT(videoCookEnd()));
connect(this, SIGNAL(videoEncode()), &encThread, SLOT(encode()));
encThread.moveToThread(&thread);
thread.start();
The above is how the whole setup is started. EncThread and thread variables are declared in the MainWindow class. I have made the set() function of EncodeThread call encode() after attempts to call encode() from the main thread using signals and QMetaObject failed.
I'm not new to threading, having used native Windows and Linux threads, as well as those of various cross-platform implementations, but QThreads really seem to baffle me. Any suggestions are more than welcome :)
Probably way to late to be any help to you, but here's a little demo program that puts an EncoderThread class to work. It probably doesn't quite mesh with your design (which your question only had fragments of), but it demonstrates running an object instance on its own thread and wiring 2 objects on different threads via signals/slots to let them communicate:
#include <stdio.h>
#include <QObject>
#include <QThread>
#include <QtCore/QCoreApplication>
// QSleeper is just a toy utility class that makes the
// protected QThread::sleep() family of functions
// publicly accessible. It's only use is for demo
// programs like this
class Sleeper : QThread
{
public:
static void sleep(unsigned long secs) { QThread::sleep(secs); }
static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
static void usleep(unsigned long usecs) { QThread::usleep(usecs); }
};
// an Encoder class that maintains itself on is own thread
class EncodeThread : public QObject {
Q_OBJECT
public:
EncodeThread();
public slots:
void encode();
signals:
void encodeProgress(int i);
void finished();
private:
QThread myThread;
};
EncodeThread::EncodeThread() {
moveToThread(&myThread);
myThread.start();
}
void EncodeThread::encode()
{
printf("EncodeThread::encode() on thread %u\n", (unsigned int) QThread::currentThreadId());
for (int i = 0; i < 6; ++i) {
// encode for 1 second or so
printf("EncodeThread::encode() working on thread %u\n", (unsigned int) QThread::currentThreadId());
Sleeper::sleep(1);
emit encodeProgress(i);
}
emit finished();
printf("EncodeThread::encode() - done\n");
}
// a controller to manage and monitor an EncoderThread instance
class VideoEncoderController : public QObject
{
Q_OBJECT
public:
void start();
public slots:
void setValue(int);
void encodingDone();
signals:
void encodingBegin();
};
void VideoEncoderController::start()
{
printf("VideoEncoderController::start() on thread %u\n", (unsigned int) QThread::currentThreadId());
emit encodingBegin();
}
void VideoEncoderController::setValue(int x)
{
printf("VideoEncoderController::setValue(int %d) on thread %u\n", x, (unsigned int) QThread::currentThreadId());
}
void VideoEncoderController::encodingDone()
{
printf("VideoEncoderController::encodingDone() on thread %u\n", (unsigned int) QThread::currentThreadId());
}
// a demo program that wires up a VideoEncoderController object to
// an EncoderThread
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
EncodeThread encThread;
VideoEncoderController controller;
QObject::connect(&encThread, SIGNAL(encodeProgress(int)), &controller, SLOT(setValue(int)));
QObject::connect(&encThread, SIGNAL(finished()), &controller, SLOT(encodingDone()));
QObject::connect(&controller, SIGNAL(encodingBegin()), &encThread, SLOT(encode()));
printf("hello world on thread %u\n", (unsigned int) QThread::currentThreadId ());
controller.start();
return a.exec();
}
#include "main.moc"
You must derive QThread, not QObject. run() method is an abstract method of QThread.
For future programmers I'm adding this answer. There are generally 3 approaches to multi-threading in Qt. Low Level, Reusing(lets say Mid Level) and High Level.
Low level also includes two different approaches. In Low level you can Inherit QThread class and provide the code that you want to run in parallel inside void QThread::run() override;. After calling QThread::start() on your drived class, code in run will execute.
Another approach in Low Level Multi-threading in Qt is relaying on Qt's event loops. In this way you create a class that is drived from QObject, not necessarily from QThread and then move that class to a new QThread with this. And after that you will call start() on that QThread object(this QThread object is an object of type QThread . You don't have to subclass QThread here. Just instantiate one object. It is where I believe you misunderstood in your code).
After calling start() on your QThread object, its event loop starts in another thread and signals from anywhere in your code that are connected to your QObject drived class's slots will run in that event loop in parallel as long as you don't use Qt::DirectConnection as last argument to this.
These two approaches has their own benefits and drawbacks. When sub-classing QThread and using Qthread::run(), if your code inside run is running inside a while(true) loop, one of your processor's threads will always be occupied with Qthread::run() code and not in the threadpool for other threads in your program.
The QObject::moveToThread() approach is useful for most cases. But if the QObject drived classe's slot is going to be called very frequently, like 100 or 1000 times per second, memory usage rises, due to possible arguments passed to the slot, and some of this signals may never reach the slot.

Resources