I need to run multiple (up to 50 or more) Qt Script Functions concurrently. Running two or three Threads with Script Functions works just fine, but as soon as I run around 50 Threads, I get an Error and my Program crashes.
ASSERTION FAILED: globalData().dynamicGlobalObject (..\3rdparty\javascriptcore\JavaScriptCore\runtime/JSGlobalObject.h:411 QTJSC::JSGlobalObject* QTJSC::ExecState::dynamicGlobalObject())
My main.cpp looks like this:
#include <QCoreApplication>
#include <QScriptEngine>
#include <threadworker.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QScriptEngine engine;
QScriptValue val = engine.evaluate("(function() {var r = Math.random(); while(1>0) print(r);})");
ThreadWorker *worker[50];
for(int i=0;i<50;i++) {
worker[i] = new ThreadWorker(val);
QObject::connect(worker[i], SIGNAL(needsStarting()), worker[i], SLOT(startScript()));
emit worker[i]->needsStarting();
}
return a.exec();
}
This is my threadworker.h:
#ifndef THREADWORKER_H
#define THREADWORKER_H
#include <QObject>
#include <QScriptValue>
#include <QThread>
class ThreadWorker : public QObject
{
Q_OBJECT
public:
explicit ThreadWorker(QObject *parent = 0);
explicit ThreadWorker(QScriptValue function);
signals:
needsStarting();
public slots:
void startScript();
private:
QScriptValue value;
QThread thread;
};
#endif // THREADWORKER_H
This is my threadworker.cpp:
#include "threadworker.h"
#include <QDebug>
ThreadWorker::ThreadWorker(QObject *parent) : QObject(parent)
{
}
ThreadWorker::ThreadWorker(QScriptValue function)
{
value = function;
this->moveToThread(&thread);
thread.start();
}
void ThreadWorker::startScript()
{
value.call();
}
I expected, that independently of the amount, the Qt Script Threads would run just fine and I can't understand what is causing this contrary behaviour.
Putting the QScriptEngine on worker class and let moveToThread move it to the the worker thread, seems to solve:
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
public slots:
void startScript(const QString &function);
private:
QScriptEngine engine;
QScriptValue value;
};
However, it will be a challenge create so many threads and release them properly on application exit. I suggest you to use pooled threads, for example, QtConcurrent. QtConcurrent allows you (for example but not limited to) multithread with just functions, not necessarly classes, and with QFutureSyncronyzer you can in one call wait for all the threads you want to finish. See QtConcurrent:
#include <QtScript>
#include <QtConcurrent>
#define THREADS 50
void worker_function(const QString &function)
{
QScriptEngine engine;
QScriptValue value;
value = engine.evaluate(function);
value.call();
}
...
QFutureSynchronizer<void> synchronizer;
//Set the max pooled threads
QThreadPool::globalInstance()->setMaxThreadCount(THREADS);
//Start all threads and add them to the future synchronizer
for (int i = 0; i < THREADS; i++)
synchronizer.addFuture(QtConcurrent::run(worker_function, QString("(function() {var r = Math.random(); while(1>0) print(r);})")));
//Wait for all threads to finish
synchronizer.waitForFinished();
...
Related
I am trying to send signal across threads.
For testing this situation, I wrote a test code.
I am working on ubuntu 16.04 machine and qt version is 4.8.
In my code, three class exists:
1 - timer_class -> in this class, I emit signal in timeout slot.
2 - test_worker -> I am using this class as thread's worker.
3 - main_class -> I create timer_class instance, and also create thread in this class constructor.
I am trying to connect timer_class signal to test_worker slot.
Here is my code:
First; timer_class :
Header File:
#ifndef TIMER_CLASS_H
#define TIMER_CLASS_H
#include <QTimer>
#include <QDebug>
#include <QObject>
class timer_class : public QObject
{
Q_OBJECT
public:
timer_class(QObject *parent = 0);
~timer_class();
void start_timer();
signals:
void dummy_signal();
private slots:
void on_timeout_occur();
private:
QTimer *timer;
};
#endif // TIMER_CLASS_H
Source File :
#include "timer_class.h"
timer_class::timer_class(QObject *parent)
:QObject(parent)
{
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(on_timeout_occur()));
}
timer_class::~timer_class()
{
}
void timer_class::start_timer()
{
timer->start(1000);
}
void timer_class::on_timeout_occur()
{
qDebug() << "timeout occur";
emit dummy_signal();
}
Second, thread_worker class :
Header File :
#ifndef THREAD_WORKER_H
#define THREAD_WORKER_H
#include <QDebug>
#include <QObject>
class thread_worker : public QObject
{
Q_OBJECT
public:
thread_worker(QObject *parent = 0);
~thread_worker();
public slots:
void main_loop();
void on_dummy_signal();
};
#endif // THREAD_WORKER_H
Source File :
#include "thread_worker.h"
thread_worker::thread_worker(QObject *parent)
:QObject(parent)
{
}
thread_worker::~thread_worker()
{
}
void thread_worker::main_loop()
{
forever
{
//qDebug() << "In Main Loop";
}
}
void thread_worker::on_dummy_signal()
{
qDebug() << "dummy signal received";
}
And last, main_class :
Header file :
#ifndef MAIN_CLASS_H
#define MAIN_CLASS_H
#include <QObject>
#include <QDebug>
#include <QThread>
#include "timer_class.h"
#include "thread_worker.h"
class main_class : public QObject
{
Q_OBJECT
public:
main_class(QObject *parent = 0);
~main_class();
private:
QThread *thread;
timer_class *tmr_class;
thread_worker *worker;
};
#endif // MAIN_CLASS_H
Source File:
#include "main_class.h"
main_class::main_class(QObject *parent)
:QObject(parent)
{
tmr_class = new timer_class();
worker = new thread_worker();
thread = new QThread();
worker->moveToThread(thread);
connect(tmr_class, SIGNAL(dummy_signal()), worker, SLOT(on_dummy_signal()));
connect(thread, SIGNAL(started()), worker, SLOT(main_loop()));
thread->start();
tmr_class->start_timer();
}
main_class::~main_class()
{
}
In main.cpp, I just create main_class instance like this :
#include <QCoreApplication>
#include "main_class.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
main_class *main_cl = new main_class();
qDebug() << "executing a.exec";
return a.exec();
}
When I run the application, I saw "timeout occur" in console, but I don't saw "dummy signal received". I can not find problem.
Could you help me about this problem ?
Thanks.
The basic problem is that you're creating a new QThread, moving your timer_class instance onto that thread and then invoking thread_worker::main_loop when the thread starts. Since thread_worker::main_loop is basically a busy-waiting loop...
void thread_worker::main_loop ()
{
forever
{
//qDebug() << "In Main Loop";
}
}
...the QThread never gets a chance to process events thus preventing any signals being received via queued connections.
The correct fix for all of this depends to a large extent on what work (if any) you want thread_worker::main_loop to do.
To get things going in the mean time simply remove the forever loop or comment out the line...
connect(thread, SIGNAL(started()), worker, SLOT(main_loop()));
Having done that you should see the "dummy signal received" messages.
I cannot produce a very simple example to getting start with Qt multi-thread. I read a lot of posts and tutorials but still it doesn't work.
Goal
Have a background worker independent from the GUI. Oh, wow...
What I did
A simple example:
create the Engine class
that shows a QMainWindow
and starts a QTimer that prints a number
But if you left-click the title bar of the GUI, keeping pressed the mouse button (i.e. on the minimize button) the counter will stop! Even if it was created in a non-GUI environment and it was moved in another thread!
Why?
main.cpp
#include "engine.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Engine e;
return a.exec();
}
engine.h
#ifndef ENGINE_H
#define ENGINE_H
#include <QObject>
#include <QThread>
#include <QTimer>
#include "mainwindow.h"
class Engine : public QObject
{
Q_OBJECT
public:
explicit Engine(QObject *parent = 0);
private:
MainWindow mainWindow;
QThread *thread;
QTimer *timer;
private slots:
void foo();
};
#endif // ENGINE_H
engine.c
#include "engine.h"
#include <QDebug>
Engine::Engine(QObject *parent) : QObject(parent)
{
thread = new QThread(this);
timer = new QTimer();
timer->setInterval(100);
connect(timer, &QTimer::timeout, this, &Engine::foo);
connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
timer->moveToThread(thread);
thread->start();
mainWindow.show();
}
void Engine::foo()
{
static int i;
qDebug() << ++i;
}
The QMainWindow contains no code.
Basically, Qt has one thread dealing with the GUI (typically the main thread). Any objects specific to this thread will be blocked by GUI work. You need to keep the GUI outside of your interacting partners.
To be more specific, your Engine object resides in the GUI/main thread. Even while your timer is sent to a worker thread, its signals are dispatched to the slot foo() in the main thread.
You need to de-mangle Engine and the main window such that Engine can reside in its own thread and process signals while the GUI is blocking.
Looks like you moved QTimer instance to your custom thread, but you didnt move Engine instance to this thread, therefore, foo slot of Engine class will be executed in main thread.
I can suggest you using additional helping QObject-derived class instance within Engine class and move it to your new thread in Engine constructor.
With following changes solution works fine even with minimize button pressed (I've commented places where i added or changed anything. Also added new QObject-derived class EngineWorker):
Engine.h
#ifndef ENGINE_H
#define ENGINE_H
#include <QObject>
#include <QThread>
#include <QTimer>
#include "mainwindow.h"
#include "engineworker.h"
class Engine : public QObject
{
Q_OBJECT
public:
explicit Engine(QObject *parent = 0);
private:
MainWindow mainWindow;
QThread *thread;
QTimer *timer;
//additional QObject-derived class
EngineWorker *worker;
private slots:
void foo();
};
#endif // ENGINE_H
Engine.cpp
#include "engine.h"
#include <QDebug>
Engine::Engine(QObject *parent) : QObject(parent)
{
thread = new QThread(this);
timer = new QTimer();
//Creating instance of Engine worker
worker = new EngineWorker();
timer->setInterval(100);
//Connecting Engine worker' foo slot to timer
connect(timer, &QTimer::timeout, worker, &EngineWorker::foo);
connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
timer->moveToThread(thread);
//Moving worker to custom thread
worker->moveToThread(thread);
thread->start();
mainWindow.show();
}
void Engine::foo()
{
static int i;
qDebug() << ++i;
}
EngineWorker.h
#ifndef ENGINEWORKER_H
#define ENGINEWORKER_H
#include <QObject>
#include <QDebug>
class EngineWorker : public QObject
{
Q_OBJECT
public:
explicit EngineWorker(QObject *parent = 0);
signals:
public slots:
void foo();
};
#endif // ENGINEWORKER_H
EngineWorker.cpp
#include "engineworker.h"
EngineWorker::EngineWorker(QObject *parent) : QObject(parent)
{
}
//foo slot of EngineWorker class
void EngineWorker::foo()
{
static int j;
qDebug() <<"Worker: "<< ++j;
}
I want to search files by name in a particular location as selected by the user. I want that as soon as I got the file. It must be put in QTreeWidget parallely and showing a QMovie(":/images/img_searching.gif") while searching is in progress until user did not stop searching.
ThreadSearch.h
#ifndef QTHREADSEARCH_H
#define QTHREADSEARCH_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QFileInfoList>
class QThreadSearchFileName : public QThread
{
Q_OBJECT
public:
QThreadSearchFileName(QObject *parent = 0);
~QThreadSearchFileName();
void run();
void getAllfiles(QStringList, QDir);
signals:
void fileInfoList(QFileInfo);
private:
QMutex m_Mutex;
QWaitCondition m_WaitCondition;
};
#endif
ThreadSearch.cpp
#include "ThreadSearch.h"
#include <QApplication>
#include <QThread>
QThreadSearchFileName::QThreadSearchFileName(QObject *parent):QThread(parent)
{
}
QThreadSearchFileName::~QThreadSearchFileName()
{
m_WaitCondition.wakeOne();
wait();
}
void QThreadSearchFileName::run()
{
QMutexLocker locker(&m_Mutex);
}
void QThreadSearchFileName::getAllfiles(QStringList targetStrList, QDir currentdir)
{
for(long int i1=0; i1<targetStrList.size(); i1++)
{
QString targetStr;
targetStr = targetStrList[i1];
QDirIterator it(currentdir, QDirIterator::Subdirectories);
while (it.hasNext())
{
QString filename = it.next();
QFileInfo file(filename);
if (file.isDir())
{ // Check if it's a dir
continue;
}
if (file.fileName().contains(targetStr, Qt::CaseInsensitive))
{
emit fileInfoList(file);
}
}
}
}
main.cpp
#include <QCoreApplication>
#include <QDebug>
#include <QDirIterator>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThreadSearchFileName *m_pSearchFileNameThread = new QThreadSearchFileName;
for(int i=0; i<userSelectedpathList.size(); i++)
{
QDir dir(userSelectedpathList[i]);
m_pSearchFileNameThread ->getAllfiles(stringListToBeSearch, dir);
connect(m_pSearchFileNameThread,SIGNAL(fileInfoList(QFileInfo)),this,SLOT(searchFileNameResult(QFileInfo)));
}
return a.exec();
}
void main::searchFileNameResult(QFileInfo file1) //Now Making SearchFile Name Tree
{
QTreeWidgetItem *SearchTreeItem = new QTreeWidgetItem(m_psearchProgresswdgt->finalSearchList_treeWidget);
SearchTreeItem->setCheckState(0,Qt::Unchecked);
SearchTreeItem->setText(1,file1.baseName());
}
It is good practice to separate such operations out from GUI object. What is more I would suggest higher-level async mechanism provided by QObject:
Make some class which could handle searching, for example
SearchingClass:
class SearchingClass : public QObject {
Q_OBJECT
public:
void setSomeSearchParametersOrSomething(QObject* something);
public slots:
void search();
signals:
void found(QObject* objectThatHasBeenFound);
}
Create instance of this class and move it into another thread:
auto searchingObject = new SearchingClass();
searchingObject->setSomeSearchParametersOrSomething(...);
auto thread = new QThread();
searchingObject->moveToThread(thread);
connect(this, SIGNAL(startSearchingSignal()), searchingObject, SLOT(search()));
connect(searchingObject, SIGNAL(found(QObject*)), this, SLOT(someHandleFoundSlot(QObject*)));
emit startSearchingSignal();
Make sure that found signal is being emitted every time that searching algorithm finds some result.
Ofc you must implement someHandleFoundSlot and declarate startSearchingSignal signal in GUI class.
I assume that you barely know Qt framework, so you should read about signals and slots as well as Qt meta-object system to fully understand whole code.
EDIT:
I see that you have edited your question. Your problem has several solution, I will describe you, what you did wrong comparably to what I had posted here.
Do not extend QThread. Extend QObject instead. It makes you can call moveToThread method. Crete an instance of QThread and pass it to this method. It causes later execution of slots to be performed in the thread you passed.
Do not make identical connections in loop until you want it to be executed more than once.
Make method getAllfiles (or search in my example) to be slot and do not call it manually. When you call method manually, it will always be performed in the same thread. Just connect it to some signal, and emit that signal.
[Just like you emit signal when you find matching file – the result is being handled in the slots objects thread.]
It's your decision, if you want to have thread for every single userSelectedpathList element. I would advice you to do it in one working thread (it's disc operations, I think it wouldn't be faster) and iterate that list inside getAllfiles method.
Previously I gave you generic answer about "how to do async work in Qt". Here's a simple implementation for your use case (I hope you will learn something).
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileInfo>
#include <QDirIterator>
#include <QThread>
#include <QDebug>
#include <QPushButton>
#include "filesearchingclass.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0){
setCentralWidget(&pushButton);
connect (&pushButton, SIGNAL(clicked(bool)), this, SLOT(main())); //invoke this->main() in event loop when button is pressed
qRegisterMetaType<QFileInfo>("QFileInfo");
searchingThread.start(); //thread must be started
}
~MainWindow(){
searchingThread.quit();
searchingThread.wait();
}
public slots:
void main() {
//EXAMPLE PARAMETERS:
QStringList pathList;
pathList.append("/home");
pathList.append("/var/log");
QStringList stringListToBeSearch;
stringListToBeSearch.append(".jpg");
stringListToBeSearch.append(".log");
//-------------------
auto fileSearchingObject = new FileSearchingClass(); //dynamic as you can't destroy object when it is out of scope
fileSearchingObject->moveToThread(&searchingThread); //important!!!
fileSearchingObject->setTargetStrList(stringListToBeSearch);
fileSearchingObject->setPaths(pathList);
connect(this,SIGNAL(startSearching()),fileSearchingObject,SLOT(search())); //do not call fileSearchingObject->search() manually
connect(fileSearchingObject,SIGNAL(foundFile(QFileInfo)),this,SLOT(searchFileNameResult(QFileInfo))); //handle every result in event loop
connect(fileSearchingObject, SIGNAL(searchFinished()), fileSearchingObject, SLOT(deleteLater())); //no need to wory about deleting fileSearchingObject now
emit startSearching(); //like calling fileSearchingObject->search() but in another thread (because of connection)
}
signals:
void startSearching();
public slots:
void searchFileNameResult(QFileInfo fileInfo) {
//do something
qDebug() << "---FOUND---" << fileInfo.absoluteFilePath() << "\n";
}
private:
QThread searchingThread;
QPushButton pushButton;
};
#endif // MAINWINDOW_H
filesearchingclass.h
#ifndef FILESEARCHINGCLASS_H
#define FILESEARCHINGCLASS_H
#include <QFileInfo>
#include <QDirIterator>
#include <QThread>
#include <QDebug>
class FileSearchingClass : public QObject {
Q_OBJECT
public:
~FileSearchingClass(){}
void setPaths (const QStringList &paths) {
userSelectedPathList = paths;
}
void setTargetStrList(const QStringList &value) {
targetStrList = value;
}
public slots:
void search() {
for(int i=0; i<userSelectedPathList.size(); i++) {
QDir currentDir(userSelectedPathList[i]);
for(long int i1=0; i1<targetStrList.size(); i1++)
{
QString targetStr;
targetStr = targetStrList[i1];
QDirIterator it(currentDir, QDirIterator::Subdirectories);
while (it.hasNext())
{
QString filename = it.next();
QFileInfo file(filename);
if (file.isDir())
{ // Check if it's a dir
continue;
}
if (file.fileName().contains(targetStr, Qt::CaseInsensitive))
{
emit foundFile(file); //calling MainWindow::searchFileNameResult directly is possible, but bad idea. This thread is only focused in searching, not modifing widgets in GUI.
}
}
}
}
emit searchFinished(); //it's always good to know when job is done.
}
signals:
void foundFile(QFileInfo);
void searchFinished();
private:
QStringList userSelectedPathList;
QStringList targetStrList;
};
#endif // FILESEARCHINGCLASS_H
I would like to create a class that has its own QTimer and QThread for some projects for Robot's sensors. After some searching, this is what I came up with
#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QObject>
#include <QDebug>
//#####################( Robot Class )#########################3
class Robot : public QObject
{
public:
Robot(QObject *parent = 0);
~Robot();
private:
QTimer *mQTimer;
QThread *mQThread;
public slots:
void update();
};
Robot::Robot(QObject *parent)
: QObject(parent)
{
mQTimer = new QTimer(0);
mQThread = new QThread(this);
mQTimer->setInterval(1);
mQTimer->moveToThread(mQThread);
connect(mQTimer, SIGNAL(timeout()), this, SLOT(update()));
connect(mQThread, SIGNAL(started()), mQTimer, SLOT(start()));
mQThread->start();
//mQTimer->start();
}
Robot::~Robot()
{
delete mQTimer;
delete mQThread;
}
void Robot::update()
{
qDebug() << "Robot is updating ...";
}
//##################( Main )###########################
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Robot *myRobot = new Robot(0);
return a.exec();
}
I'm getting this error
QObject::connect: No such slot QObject::update() in ..\untitled1\main.cpp:34
QObject::connect: No such slot QObject::update() in ..\untitled1\main.cpp:34
You are missing the Q_OBJECT macro in your class also try to avoid naming the methods like that because you can mix it with Qt methods names. Also make additional header and cpp file for each class you create in this case make robtot.h and robot.cpp.
class Robot : public QObject
{
Q_OBJECT
public:
Robot(QObject *parent = 0);
~Robot();
...
The below works for me. You forgot the Q_OBJECT macro and to include the moc output that defines the static metadata for Robot.
There's of course no point to this code, since the Robot::update slot will execute in the main thread.
Your code has two threads: the main thread, where the Robot object lives, and the robot.mThread, where the timer lives. The timer will time out in the mThread, and will queue a slot call on the main thread. That slot call will end up invoking robot.update with a.exec on the stack.
Note that there's no need to explicitly have the timer and the thread allocated on the heap using new. They should be direct members of Robot, or of its PIMPL.
main.cpp
#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>
class Robot : public QObject
{
Q_OBJECT
QTimer mTimer;
QThread mThread;
public:
Robot(QObject *parent = 0) : QObject(parent) {
connect(&mTimer, &QTimer::timeout, this, &Robot::update);;
mTimer.start(1000);
mTimer.moveToThread(&mThread);
mThread.start();
}
Q_SLOT void update() {
qDebug() << "updating";
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Robot robot;
return a.exec();
}
#include "main.moc"
It would make more sense to move the entire robot to its own thread. Note that when you do that, you need to set parentage on all objects owned by robot, so that they all switch threads along with the Robot object.
The Thread class fixes the long standing usability bug of QThread - it turns it into a truly RAII class that can be safely destructed at any time.
main.cpp
#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>
class Thread : public QThread {
using QThread::run;
public:
~Thread() { quit(); wait(); }
};
class Robot : public QObject
{
Q_OBJECT
QTimer mTimer;
int mCounter;
public:
Robot(QObject *parent = 0) : QObject(parent), mTimer(this), mCounter(0) {
connect(&mTimer, &QTimer::timeout, this, &Robot::update);;
mTimer.start(1000);
}
Q_SLOT void update() {
qDebug() << "updating";
if (++mCounter > 5) qApp->exit();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Robot robot;
Thread thread;
robot.moveToThread(&thread);
thread.start();
return a.exec();
}
#include "main.moc"
Say, I have 2 threads: A and B, A is the main thread. In thread A, there are two on_button_click slots. The first one is:
on_button_one_clicked(){
myObject_one = new myObject(this);
myObject_one->setParent(map);
myObject_two = new myObject(this);
myObject_two->setParent(map);
...
}
The second one is:
on_button_two_clicked(){
foreach(myObject* i, map->childItems){
delete i;
}
}
Here, myObject and map are all QGraphicsItems. In thread B, a signal is emitted to trigger a slot of thread A:
slot_triggered_by_signal_from_thread_B(){
foreach(myObject* i, map->childItems){
i->do_some_thing();
}
}
Is this safe? Will it happen, when the codes comes to the line i->do_some_thing and meet an empty pointer and crash?
It is safe as long as you use the auto connection or queued conncetion type between the threads since then the slot will be only invoked when your other slot is finishing up or vice versa. They will not be running "simultaneously". That is the only concern that I could imagine for this not to be safe enough. I believe you meant a scenario like this:
main.cpp
#include <QThread>
#include <QApplication>
#include <QTimer>
#include <QObject>
#include <QPushButton>
#include <QDebug>
class Work : public QObject
{
Q_OBJECT
public:
explicit Work(QObject *parent = Q_NULLPTR) : QObject(parent) { QTimer::singleShot(200, this, SLOT(mySlot())); }
public slots:
void mySlot() { emit mySignal(); }
signals:
void mySignal();
};
class MyApplication : public QApplication
{
Q_OBJECT
public:
explicit MyApplication(int argc, char **argv)
: QApplication(argc, argv)
, pushButton(new QPushButton())
{
QStringList stringList{"foo", "bar", "baz"};
QThread *workerThread = new QThread();
Work *work = new Work();
work->moveToThread(workerThread);
connect(pushButton, &QPushButton::clicked, [&stringList] () {
for (int i = 0; i < stringList.size(); ++i)
stringList.removeAt(i);
});
connect(work, &Work::mySignal, [&stringList] () {
for (int i = 0; i < stringList.size(); ++i)
qDebug() << stringList.at(i);
});
}
~MyApplication()
{
delete pushButton;
}
QPushButton *pushButton;
};
#include "main.moc"
int main(int argc, char **argv)
{
MyApplication application(argc, argv);
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Let's assume that main thread does some heavy work in on_button_two_clicked function.
Any other actions include user do something or another request from other thread
(in this case slot_triggered_by_signal_from_thread_B) will be blocked until
finishing on_button_two_clicked.
I think it means that it guarantees finishing previous event.
In conclusion, it is safe!