I have a main thread that invokes a child thread function at different times but I am not sure whether that is right way of doing it in Qt.What is wrong with the below code and looking for better alternative
There is a main thread running infinitly when ever main thread releases the lock child does a piece of work.
#include <QtCore/QCoreApplication>
#include <QSemaphore>
#include <QThread>
QSemaphore sem(0);
class Background : public QThread
{
protected:
void run()
{
for(;;)
{
sem.acquire(1);
qDebug("Child function ran");
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Background child;
child.start();
qDebug("Main running");
qDebug("release a lock");
sem.release(1);
qDebug("Do somework in main");
//call child
sem.release(1);
sem.release(1);
return a.exec();
}
Edit: rework of entire post to cover basics as well.
Background.h:
#ifndef BACKGROUND_H
#define BACKGROUND_H
#include <QThread>
#include <QObject>
class Background : public QThread
{
Q_OBJECT
public:
Background(QObject* parent = 0):QThread(parent){}
protected:
void run()
{
qDebug(qPrintable(QString("Child function ran in thread: %1").arg(QThread::currentThreadId())));
}
};
class BackgroundConcurrent : public QObject
{
Q_OBJECT
public:
BackgroundConcurrent(QObject* parent = 0):QObject(parent){}
public slots:
void doWork() const
{
qDebug(qPrintable(QString("Concurrent child function ran in thread: %1").arg(QThread::currentThreadId())));
}
};
class BackgroundTrigger : public QObject
{
Q_OBJECT
public:
BackgroundTrigger(QObject* parent = 0):QObject(parent){}
~BackgroundTrigger()
{
foreach(QObject* child, children())
{
QThread* childThread = qobject_cast<QThread*>(child);
if (childThread)
childThread->wait();
}
}
public slots:
void triggerWorker()
{
Background* child = new Background(this);
child->start();
}
};
#endif // BACKGROUND_H
main.cpp:
#include "Background.h"
#include <QCoreApplication>
#include <QtConcurrentRun>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Using QThread
BackgroundTrigger childTrigger;
qDebug(qPrintable(QString("Main function ran in thread: %1").arg(QThread::currentThreadId())));
// Call child
childTrigger.triggerWorker();
childTrigger.triggerWorker();
// Using QtConcurrent
BackgroundConcurrent cchild;
QFuture<void> future1 = QtConcurrent::run(&cchild, &BackgroundConcurrent::doWork);
QFuture<void> future2 = QtConcurrent::run(&cchild, &BackgroundConcurrent::doWork);
return 0;
}
Sample output:
Main function ran in thread: 1087038064
Child function ran in thread: 1091267472
Child function ran in thread: 1093417872
Concurrent child function ran in thread: 1095519120
Concurrent child function ran in thread: 1097644944
Be sure you run moc on your header files, qmake and cmake both support creating your makefiles.
Here is the CMakeLists.txt file I used to build the code:
cmake_minimum_required(VERSION 2.6)
#Project name
project(TEST)
#Use Qt4
find_package(Qt4)
if(QT4_FOUND)
set(QT_USE_QTOPENGL TRUE)
include(${QT_USE_FILE})
set(LIBS
${QT_LIBRARIES}
)
#Source files (*.cpp, *.o)
set(TEST_SRCS main.cpp)
#Header files (*.h[pp])
set(TEST_HDRS Background.h)
#Qt macros to handle uic, moc, etc...
QT4_WRAP_CPP(TEST_MOC ${TEST_HDRS} OPTIONS -nw)
set(TEST_ALLSRC ${TEST_SRCS} ${TEST_MOC})
#Create main
add_executable(test ${TEST_ALLSRC})
target_link_libraries(test ${LIBS})
endif(QT4_FOUND)
Actually your current solution to the problem is quite a nice hack.
If you prefer to do it in a "cleaner" fashion, you should start an event loop in your worker thread. Then the worker thread will be able to receive signals from the main thread. You could call a function in the child thread (using signal/slot mechanism) from the main thread to trigger operation.
See here for more details:
http://doc.trolltech.com/4.2/threads.html#per-thread-event-loop
(Hint: The key idea is that you create the receiving object in the worker thread; then its slots will be processed in that thread; or you could use MoveToThread() function)
It seems that you might want to use a signal for that, to fit in with the normal Qt style. Check out this question; the accepted answer there seems to match your question too.
Related
I'm working on a C++ Qt GUI to remote control a ROS robot. I've read that the ros::spin() command should be issued in a seperate Thread so I basically have the usual MainWindow derived from QMainWindow whose constructor sets up the GUI elements, makes the Subscriber Objects subscribe to their respective topic (e.g. image_transport::Subscriber for sensor_msgs/Image topics) and also starts another Thread. For that I have derived a "RosThread" class from QThread that doesn't do anything but starting a ros:MultiThreadedSpinner when RosThread::run() is called.
As you can probably tell, I'm not exactly experienced when it comes to programming in general so my question is, wether the basic concept behind my project makes any sense to you?
Especially should I leave the NodeHandle and the Subscriber Objects in the MainWindow and setup the Subscriptions from the MainWindow Constructor?
Relevant code snippets:
mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), itLeft(nh), itArm(nh)
{
//subscribe to cameras
imageSubLeft = itLeft.subscribe("/camera_1/image_raw", 1000, &MainWindow::camCallbackLeft, this);
imageSubArm = itArm.subscribe("/camera_2/image_raw", 1000, &MainWindow::camCallbackArm, this);
pagestack = new QStackedWidget;
page1 = new QWidget;
grid = new QGridLayout;
page1->setLayout(grid);
pagestack->addWidget(page1);
labelLeft = new QLabel;
labelMid = new QLabel;
grid->addWidget(labelLeft, 0, 0);
grid->addWidget(labelMid, 0, 1);
this->startSpinThread(); //starts the seperate Thread where run() is executed
this->setCentralWidget(pagestack);
this->setWindowState(Qt::WindowMaximized);
this->setMinimumSize(1024, 768);
}
MainWindow::~MainWindow(){}
void MainWindow::camCallbackLeft(const sensor_msgs::Image::ConstPtr &msg){/*some code*/}
void MainWindow::camCallbackArm(const sensor_msgs::Image::ConstPtr &msg){/*some code*/}
void MainWindow::closeEvent(QCloseEvent *event){/*some code*/}
void MainWindow::startSpinThread()
{
if(rosSpin.isRunning())
{
return;
}
//rosSpin is an Object of the of QThread derived class
rosSpin.start();
}
rosthread.h:
#ifndef ROSTHREAD_H
#define ROSTHREAD_H
#include <ros/ros.h>
#include <QThread>
class RosThread : public QThread
{
Q_OBJECT
public:
RosThread();
protected:
void run();
private:
ros::MultiThreadedSpinner spinner;
};
#endif // ROSTHREAD_H
rosthread.cpp:
#include "rosthread.h"
RosThread::RosThread()
{
}
void RosThread::run() {
spinner.spin();
}
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <ros/ros.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "gui_node");
QApplication app (argc, argv);
MainWindow *win = new MainWindow();
win->show();
return app.exec();
}
Actually, QThread is not intended to be used this way. Take a look at this blog article and this example.
But anyway, I would suggest the standard C++ threads.
Add std::unique_ptr<std::thread> thread; to your MainWindow class instead of the RosThread object.
To start a thread, use thread.reset(new std::thread([](){ static ros::MultiThreadedSpinner spinner; spinner.spin(); });. The smart pointer std::unique_ptr will automatically delete the thread object although you shouldn't forget to use std::thread::join() or std::thread::detach() before the resetting/destroying your std::unique_ptr object.
Another solution would be to put the ros::MultiThreadedSpinner object into your MainWindow class and create a std::thread using thread.reset(new std::thread(&ros::MultiThreadedSpinner::spin, spinner));.
In my opinion, you should put you NodeHandle and Subscriber objects into another class and use an object of this class as a member of MainWindow if they don't belong directly to MainWindow.
I am working on a data logger in QT framework. I Intend to save log strings to files and print to the console in a separate watcher thread. In that separate thread I need to watch my QStringList for new items added. If there are new items I deque them and log. I was wondering what is the mechanism used for this in Qt framework. In STD lib i used condition_variable for this task like this:
/*!
* \brief puts a \ref logline_t object at the end of the queue
* #param s object to be added to queue
*/
void CLogger::push_back(logline_t* s)
{
unique_lock<mutex> ul(m_mutex2);
s->queSize = m_data.size();
m_data.emplace_back(move(s));
m_cv.notify_all();
}
/*!
* \brief takes a \ref logline_t object from the beggining of the queue
* #return first \ref logline_t object
*/
CLogger::logline_t CLogger::pop_front()
{
unique_lock<mutex> ul(m_mutex2);
m_cv.wait(ul, [this]() { return !m_data.empty(); });
assert(m_data.front());
logline_t retVal = move(*m_data.front());
delete m_data.front();
m_data.front() = NULL;
m_data.pop_front();
return retVal;
}
m_cv is the conditional variable object. How can this functionality be acquired with QT? I bet there is a lot better way :). I would appreciate all help.
Ps: I know pointer functions parameters are not asserted, this is an old code... :P
There are a couple of ways of doing the notification in Qt.
Signals and Slots
Signals and slots can be sent between threads, when making the connection, you set the connection type to Qt::QueuedConnection or Qt::BlockingQueuedConnection.
You may want to create a wrapper class around the QStringList so that modifications can trigger the signals that other classes listen for.
QMutex and QWaitCondition
You can use the Qt thread synchronisation classes QMutex and QWaitCondition to do the classic manual synchronisation like you have done previously. When using QMutex, the QMutexLocker is useful for scope lock and release of a QMutex.
Here's an example of doing this signals and slots. You may want to do your own benchmarks to test whether this fits your needs. Please also note that while signals and slots guarantee thread-safety, they don't guarantee that the messages will appear in the same order they were sent. That being said, I've used this mechanism for years and it has yet to happen for me.
First, create a couple of classes:
Loggee
// loggee.hpp
#ifndef LOGGEE_HPP
#define LOGGEE_HPP
#include <QObject>
class Loggee : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
void someEventHappened(int id);
signals:
void newLogLineNotify(QString const&);
};
#endif // LOGGEE_HPP
and the .cpp file:
#include "loggee.hpp"
void Loggee::someEventHappened(int id)
{
auto toLog = QString::number(id);
emit newLogLineNotify(toLog);
}
Logger
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include <QObject>
class Logger : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
signals:
public slots:
void onLogEventHappened(QString const&);
};
#endif // LOGGER_HPP
and the .cpp file:
#include <QDebug>
#include <QThread>
#include "logger.hpp"
void Logger::onLogEventHappened(QString const& str)
{
qDebug() << QThread::currentThreadId() << str;
}
the rest
#include <QDebug>
#include <QThread>
#include <QCoreApplication>
#include <QTimer>
#include "logger.hpp"
#include "loggee.hpp"
int main(int argc, char** argv)
{
QCoreApplication a(argc, argv);
QThread t;
t.start();
Logger foo;
Loggee bar;
foo.moveToThread(&t);
QObject::connect(&bar, &Loggee::newLogLineNotify,
&foo, &Logger::onLogEventHappened,
Qt::AutoConnection);
qDebug() << "Current thread id: " << QThread::currentThreadId();
bar.someEventHappened(42);
QTimer::singleShot(3000, [&]{ bar.someEventHappened(43); });
return a.exec();
}
In this demo, I create a QThread and a Logger, move handling of this new Logger's slots to this new thread's event loop. Then I connect Loggee's signal with Logger's slot using Qt::AutoConnection. This is the default but I stated it explicitly to show that you can change this (i.e. to Qt::QueuedConnection which would queue the execution of the slot even if both threads lived in the same thread).
Then I cause the Loggee to emit¹ a singal. It gets properly scheduled and causes the logging slot to be executed in the receiver's thread.
¹ emit is #define emit /*null*/, so you can omit it if you want
If you are just looking for the Qt equivalents to the classes you have been using:
std::mutex -> QMutex
std::condition_variable -> QWaitCondition
std::unique_lock -> QMutexLocker
I try to create something like a window pool. You can use these windows everywhere in your program to display graphics and plot diagrams etc. The widgets working well but the main problem at the moment is the frustrated tries, to create the pool. One non QObject-Object should represent a QMainWindow to cut the bindings to Qt.
I cannot create a widget -> I tried invokeMethode, connect and QTimer but nothing works. Sometimes the methods don´t get called or I am not in the gui thread... Any idea?
Edit 2 - new version:
header:
#pragma once
#include <QMainWindow>
#include <QTimer>
class MyWindow : QObject
{
Q_OBJECT
public:
MyWindow();
};
class QWindowPool : public QObject
{
Q_OBJECT
public:
QWindowPool();
public slots:
void createWindow();
};
class QWindow : public QMainWindow
{
Q_OBJECT
};
cpp:
#include
#include <QApplication>
#include <QTimer>
#include <QtConcurrent/qtconcurrentrun.h>
#include <iostream>
#include <future>
static QWindowPool *pool = new QWindowPool();
QWindowPool::QWindowPool() {
// check if app is running
if (!QApplication::instance()) {
bool appOnline = false;
QtConcurrent::run([&appOnline](){
int c = 0;
new QApplication(c, NULL);
appOnline = true;
qApp->exec();
});
while (!appOnline) {}
}
moveToThread(QApplication::instance()->thread());
}
void QWindowPool::createWindow() {
printf("window created\n");
new QWindow();
}
MyWindow::MyWindow() {
QTimer::singleShot(0, pool, SLOT(createWindow()));
}
int main()
{
MyWindow mw;
std::thread t1([](){
MyWindow mw;
std::thread t2([](){
MyWindow mw;
});
t2.join();
});
t1.join();
std::cin.ignore();
return 0;
}
Now the code do what is should. I can create widgets in different threads. But there are two scenarios, where I would stack at:
Someone (anyone who would like to use this library) creates before me QApplication and never calls qApp->exec
Someone want to create an own UI with Widget but does not work in my qt::concurrent gui thread. He would probably not get along with this.
What I want is in the final application:
The user should get the possibility to write anywhere in his code and in any thread:
MyWindow mw(dataToDisplay)
and the window should be created and showed to him.
Qt will only let you create widgets from the main GUI thread, this is explicitly mentioned in the docs (emphasis mine):
As mentioned, each program has one thread when it is started. This
thread is called the "main thread" (also known as the "GUI thread" in
Qt applications). The Qt GUI must run in this thread. All widgets and
several related classes, for example QPixmap, don't work in secondary
threads. A secondary thread is commonly referred to as a "worker
thread" because it is used to offload processing work from the main
thread.
I need your advice on a program I'm coding right now. Let me first present you what it is.
Design
I'm designing a man-machine interface (MMI). In this MMI, there are two core elements:
The MainWindow:
This MainWindow is the base of everything. Important: Here, I launch in a thread a server that receives the data from a client. This data is very important to the next element.
Supervision
This window contains a QTableWidget, the goal is to show in pseudo-real time the data received on the server in the thread of MainWindow.
The Problem
The server in the thread owned by the MainWindow receive a structure every 10 mS. How can I send these data to the Supervision window if it's open? I was thinking of using shared memory, but not really sure about this, and doesn't really which method I have to use.
Some Solutions
I tried to implement the solution of Sebastian Lange :
An emit in the thread Server
A connect in the MainWindow
A slot in supervision
So now my thread Server emit a signal at every frame received. But how can I do the connect in the MainWindow and how will Supervision receive the struct emit in the signal?
Here's the code of my emit:
MainWindow* MainWindow::m_psMainWindow = nullptr; // C++ 11 nullptr
void MainWindow::emit_signal_TrameRecu(StructureSupervision::T_StructureSupervision* ptr){
emit signal_TrameRecu(ptr);
}
void MainWindow::lancerServeur(std::atomic<bool>& boolServer){
serveur s;
StructureSupervision::T_StructureSupervision* bufferStructureRecu;
while(boolServer){
bufferStructureRecu = s.receiveDataUDP();
if(bufferStructureRecu->SystemData._statutGroundFlight != 0){
m_psMainWindow->emit_signal_TrameRecu( bufferStructureRecu );
}
}
}
Queued Connections
Qt makes cross thread communication easy when you use queued connections.
Your calls to connect should use the Qt::QueuedConnection or Qt::BlockingQueuedConnection connection types.
Custom Types in Slots and Signals
To use custom types (structs) in slots, signals, QVariant and properties you need to declare and register the type to make it available to the Qt dynamic type system.
In your header (.hpp) use Q_DECLARE_METATYPE and in your source (.cpp) use qRegisterMetaType.
Worked Example
server.hpp
#ifndef SERVER_HPP
#define SERVER_HPP
#include <QtCore>
struct customdata
{
int id;
QDateTime tstamp;
};
Q_DECLARE_METATYPE(customdata)
class Server : public QThread
{
Q_OBJECT
public:
Server();
signals:
void sendData(const customdata& d);
protected:
virtual void run();
};
#endif
server.cpp
#include "server.hpp"
static const int customdata_metatype_id =
qRegisterMetaType<customdata>();
Server::Server() : QThread() {}
void Server::run()
{
customdata d;
d.id = 0;
for (int i = 0; i < 10; ++i)
{
d.id++;
d.tstamp = QDateTime::currentDateTime();
emit sendData(d);
sleep(1);
}
}
window.hpp
#ifndef WINDOW_HPP
#define WINDOW_HPP
#include <QtGui>
#include "server.hpp"
class Window : public QWidget
{
Q_OBJECT
public:
Window();
public slots:
void receiveData(const customdata& d);
private:
QListWidget* mList;
};
#endif
window.cpp
#include "window.hpp"
Window::Window() : QWidget(),mList(new QListWidget())
{
resize(400, 300);
QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->addWidget(mList);
setLayout(mainLayout);
}
void Window::receiveData(const customdata& d)
{
QString str(QString("%1 %2").arg(d.id).arg(d.tstamp.toString()));
mList->addItem(str);
}
main.cpp
#include <QtGui>
#include "server.hpp"
#include "window.hpp"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Window win;
Server ser;
QObject::connect(
&ser, SIGNAL(sendData(customdata)),
&win, SLOT(receiveData(customdata)),
Qt::QueuedConnection);
win.show();
ser.start();
return app.exec();
}
test.pro
TEMPLATE=app
QT=core gui
HEADERS=server.hpp window.hpp
SOURCES=main.cpp server.cpp window.cpp
I once (in the days of Qt 3.2) implemented this cross thread communication using QApplication::postEvent (now QCoreApplication::postEvent). However nowadays best practise is to use promises and futures to communicate asynchronously between threads. Promises and futures has become a part of recent C++ standard and the concepts are also implemented separately as part of Qt 5 Concurrent framework. See http://qt-project.org/doc/qt-5/qtconcurrent-index.html
In the following function, manager will emit finished(QNetworkReply*) signal, then the slot function getCategories(QNetworkReply*) will be called.
void getCategories()
{
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(getCategories(QNetworkReply*)));
for(int i = 0; i < stores.size(); ++i)
{
request.setUrl(QUrl(QString("http://www.example.com/%1").arg(stores[i].store_id)));
manager.get(request);
}
}
If the second signal emitted when the first call of the slot function, does Qt start another thread to run the slot function as the response to the second signal? And if it is so, is there some method to let the second call of slot function wait until the first call is finished?
UPDATE:
I mean is there a possibility that the slot function run in the same time?
Unless you create them explicitly, there's no "visible" multi-threading in a Qt program. That means, Qt might use threads internally for e.g. network I/O, but that multithreading is shielded from you and you don't have to care about it. None of your code will be called from other threads, nor will your data be shared with other threads by means that would require you to care about synchronization.
Signal/slot connections come it two main flavors: direct and queued connections:
Direct connections are just function calls that are executed synchronously, with some extra function calls and lookup tables in between. If you emit a signal, all slots are called immediately, before the "emit signal();" returns (as Laszlo's example demonstrates).
Queued connections on the other hand are also executed on the main thread, without any parallelism/multi-threading. However, the slot calls are enqueued in the event loop's event queue: The method doing the emit is completed first, the control returns to the event loop, which then at some later point in time calls the slot(s). The slots are called one after another - the order of execution might not be defined, but they will never be called in parallel.
Now QNetworkAccessManager (QNAM) also works event-driven (*), with queued events: You call get(), the control returns to the event loop; the QNAM sends the request; later, after performing the network I/O, the response is received by QNAM. Think of the network I/O and completion of the response as events, like e.g. mouse clicks: The event occurs, it is put into the event queue, later the event loop calls some internal slot in QNAM, which then triggers finished() to be emitted and mySlot() to be called.
(*) In fact, depending on the platform, QNAM might indeed use multithreading. But that's an implementation detail hidden from the user - so one can stick to the "event-driven" mental model.
It does not start it in a second thread. AFAIK, it will be either a direct call or queued for handling by default. The situation also depends on how you are managing your threads.
There are several connection types you can choose from, but usually, the default (direct or queued) should be fine.
I will show you two examples to demonstrate that it also depends on what exactly emits the signal.
Case 1 (Emitted by the slot being executed)
main.cpp
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QCoreApplication>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0) : QObject(parent), counter(0)
{
connect(this, SIGNAL(mySignal()),
this, SLOT(mySlot()), Qt::QueuedConnection);
}
signals:
void mySignal();
public slots:
void mySlot()
{
if (counter >= 2) return;
++counter;
qDebug() << "mySlot started";
emit mySignal();
QThread::msleep(1000);
qDebug() << "mySlot quit";
}
private:
int counter;
};
#include "main.moc"
int main(int argc, char **argv)
{
QCoreApplication application(argc, argv);
MyClass myObject;
myObject.mySlot();
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = test
QT = core
SOURCES += main.cpp
Build and Run
moc -o main.moc main.cpp && qmake && make && ./test
Output
mySlot started
mySlot quit
mySlot started
mySlot quit
You would get the following output without queued connection to indicate that it would be a direct call in the middle of the slot execution in my example:
mySlot started
mySlot started
mySlot quit
mySlot quit
Case 2 (not emitted by the slot being executed)
main.cpp
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QCoreApplication>
#include <QTimer>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0) : QObject(parent), counter(0), timer(new QTimer(this))
{
// Note: there is no need for queued connection in this case
connect(this, SIGNAL(mySignal()), this, SLOT(mySlot()));
connect(timer, SIGNAL(timeout()), this, SLOT(mySlot()));
timer->setSingleShot(true);
timer->start(200);
}
signals:
void mySignal();
public slots:
void mySlot()
{
++counter;
qDebug() << "mySlot started" << counter;
QThread::msleep(1000);
qDebug() << "mySlot quit" << counter;
}
private:
int counter;
QTimer *timer;
};
#include "main.moc"
int main(int argc, char **argv)
{
QCoreApplication application(argc, argv);
MyClass myObject;
myObject.mySlot();
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = test
QT = core
SOURCES += main.cpp
Build and Run
moc -o main.moc main.cpp && qmake && make && ./test
Output
mySlot started 1
mySlot quit 1
mySlot started 2
mySlot quit 2