I'm trying to create a periodic callback using QT. I'm thinking, something like OpenGL's periodic callback.
Basically, I have a micro controller which is waiting for an event to happen. When the event Happens it sends the time over the serial port to the PC. On the PC side, I want the GUI to update whenever this time information is received, or to periodically check to see if there is anything in the Rx buffer.
Is there any built in functionality of Qt to periodically call a methood?
If not is there a way to create a signal between QextSerial, and The GUI?
Or, will I have to make a multi-threaded app with an observer/observable relationship between the serialPort, and the GUI?.
Have a look at QTimer. They also list an example of an analog clock
For my specific needs I ended up using a QextSerialPort.
I attached a signal to the Port so that whenever a message was received it would add the time to the Model, and update the GUI.
Port = new QextSerialPort();
//... various Port Setup
connect(Port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
This way I was able to keep the Data Model and GUI more separated.
You could try using QSocketNotifier.
I've used it to read and process standard input. You just need to change your the file you read from (in my case STDIN_FILENO)
---hpp
class QSocketNotifier;
class ConsoleReader : public QObject
{
Q_OBJECT
public:
explicit ConsoleReader(QObject *parent = 0);
Q_SIGNALS:
void textReceived(QString message);
public Q_SLOTS:
void text();
private:
QSocketNotifier* notifier;
};
---cpp
#include <QSocketNotifier>
#include <unistd.h> //Provides STDIN_FILENO
ConsoleReader::ConsoleReader(QObject *parent)
: QObject(parent)
{
notifier = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read);
connect(notifier, SIGNAL(activated(int)), this, SLOT(text()));
}
void ConsoleReader::text()
{
QTextStream qin(stdin);
QString line = qin.readLine();
Q_EMIT textReceived(line);
}
Related
I'm working on a small project with Qt (for learning Qt and bit of c++ exercise) and what I want to achieve is a clone of "online coding editors" which multiple users can read and edit a document. Doesn't have to be online, main purpose is to handle concurrent file editing. I just don't know how to approach this task.
What I have done till now is to build a simple text editor. Program has two text areas. In text area 1 you write your code. In text area 2 it shows the output. When you run your code it saves the contents of the text area 1 to a file (Code.cpp for example) then compile the saved file. When it compiled, another function runs the exe and writes the output to another file(This done in powershell's Out-File command). text area 2 just reads the content of the output file.
For single user this works. The problem is I don't know how to handle when there are multiple users. Someone suggested me that I should use text editor program as a client and handle concurrent operations in a server. That seems like a nice approach. Does that mean I should also handle the save file and run code option on the server?
And how do I do let multiple users edit the same file? Obviously I'm not asking for a -real- code. I know mutexes and semaphores but never implemented one. Some pseudo code might help maybe? I don't know where to start to dig up so here I am. I would really appreciate if someone can point me a direction (any books to read or tutorials... etc)
Take a look at QThread and Qt Signals/Slots. Let's say you have a main program that has an editor and a save command. This is your main thread. Your save command is executed in a worker thread, an instance of QThread that can run next to your main thread. When the user clicks save, your worker thread will send a Qt Signal saying that the save command was executed. Your main thread can then refresh the file contents. Now because you use QThread and Qt Signals you will not need any mutex or semaphore or any kind of resource locking because that's already done for you. You can see this as thread safe.
The following example was directly taken from the Qt docs: https://doc.qt.io/qt-5/qthread.html
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
Disclaimer: I am relatively new to Qt and any type of programming that revolves around Threads and Networking. I have also adopted a lot of code from Qt Examples, API, and other online examples.
All code can be found on GitHub. This code is relatively as simple as it can get minus striping out GUI. I figure supplying it this way would help as well versus just pasting the code below.
I want to use and believe I need to use Threads as I need multiple clients send a request to the server, the server run some SQL code, then spit out the results back to the client (basically deriving a MySQL Server, but specific to what I am doing). Right now though, I am just working on learning the workings of it all.
With all that being said, as the Title states.. My client can connect to the server, the server sets up the thread, and will receive data (a String) through the readReady. After the data is read in, for right now I am just trying to echo it back to the client. It will do this, but only once. Then it spits out:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x266cca92ea0), parent's thread is serverThread(0x266cca9ed60), current thread is QThread(0x266cac772e0)
I cannot send any further data to the server unless I have the client reconnect, then after the data is sent, it will do its job but then spit out the same error and cease functioning. I have tried quite a bit of different things, but cannot seem to fix the issue. I even tried setting up a SIGNAL/SLOT for this as suggested in API:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
Anyway, any help would be greatly appreciated! My Code is below..
Server
ServerThread.cpp
// Project
#include "ServerDialog.h"
#include "ServerThread.h"
ServerThread::ServerThread(qintptr _socketDiscriptor, QObject *parent /*= 0*/)
: QThread(parent)
{
socketDiscriptor = _socketDiscriptor;
}
void ServerThread::run()
{
emit threadStarted(socketDiscriptor);
// Start Thread
clientSocket = new QTcpSocket;
// Set SocketDisc
if (!clientSocket->setSocketDescriptor(socketDiscriptor))
{
emit error(clientSocket->error());
return;
}
// Connect Socket and Signal
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
//// Loop Thread to Stay Alive for Signals and Slots
exec();
}
void ServerThread::readyRead()
{
QDataStream in(clientSocket);
in.setVersion(QDataStream::Qt_5_7);
in.startTransaction();
QString dataReceived;
in >> dataReceived;
if (!in.commitTransaction())
{
emit readyReadError(socketDiscriptor);
return;
}
emit readyReadMessage(socketDiscriptor, dataReceived);
echoData(dataReceived);
}
void ServerThread::disconnected()
{
emit threadStopped(socketDiscriptor);
clientSocket->disconnect();
clientSocket->deleteLater();
this->exit(0);
}
void ServerThread::echoData(QString &data)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
clientSocket->write(block);
}
So in ServerThread.cpp when echoData is called, that is when the error shows up and the Socket ceases functioning.
Any and all help will be appreciated. I know there are a few other posts regarding "Cannot create children for..." in regards to Threads. But I did not find any of them helpful. The one thing that I did find interesting but did not understand was maybe using moveToThread() but a lot of mixed comments on that.
I learn best through code examples along with explanation versus just an explanation or pointer to API. Thank you!
Most of Qt network functions are asynchronous; they do not block the calling thread. There is no need to mess up with threads if you are using QTcpSockets. In fact, creating a thread for every socket is an overkill, since that thread will spend most of its time just waiting for some network operation to finish. Here is how I would implement a single-threaded echo server in Qt:
#include <QtNetwork>
#include <QtCore>
//separate class for the protocol's implementation
class EchoSocket : public QTcpSocket{
Q_OBJECT
public:
explicit EchoSocket(QObject* parent=nullptr):QTcpSocket(parent){
connect(this, &EchoSocket::readyRead, this, &EchoSocket::EchoBack);
connect(this, &EchoSocket::disconnected, this, &EchoSocket::deleteLater);
}
~EchoSocket() = default;
Q_SLOT void EchoBack(){
QByteArray receivedByteArray= readAll();
write(receivedByteArray);
disconnectFromHost();
}
};
class EchoServer : public QTcpServer{
public:
explicit EchoServer(QObject* parent= nullptr):QTcpServer(parent){}
~EchoServer() = default;
//override incomingConnection() and nextPendingConnection()
//to make them deal with EchoSockets instead of QTcpSockets
void incomingConnection(qintptr socketDescriptor){
EchoSocket* socket= new EchoSocket(this);
socket->setSocketDescriptor(socketDescriptor);
addPendingConnection(qobject_cast<QTcpSocket*>(socket));
}
EchoSocket* nextPendingConnection(){
QTcpSocket* ts= QTcpServer::nextPendingConnection();
return qobject_cast<EchoSocket*>(ts);
}
};
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
EchoServer echoServer;
echoServer.listen(QHostAddress::Any, 9999);
QObject::connect(&echoServer, &EchoServer::newConnection, [&](){
EchoSocket* socket= echoServer.nextPendingConnection();
qDebug() << "Got new connection from: " << socket->peerAddress().toString();
});
return a.exec();
}
#include "main.moc"
Notes:
This server has the ability to handle more than one client at the same time, since there is no blocking. The thread will just respond to the event that happens with the appropriate action; So, if that event was a new connection, it will create a new EchoSocket object to handle it and prints a statement out to qDebug(), and if that event was receiving something on a previously created socket, the same thread will echo received data back and close the connection. It will never block on a single connection waiting for data to arrive nor it will block waiting for a new connection to arrive.
Since you mention using some SQL queries in response for some connections later in your project. Please avoid threading since an SQL database connection in Qt can be used only from the thread that created it, see docs here. So, You'll have to either create a new database connection for each thread (and thus for each connection) in your application (and this is beyond just overkill), or switch later to a single threaded design.
In this section, I am explaining why threading does not work for you the way you are doing it:
You should not be declaring slots in your QThread subclass, Instead, use worker QObjects and move them to QThreads as needed.
The quote you have provided in your question is the exact explanation for why you get this warning. The ServerThread instance you create will be living in the main thread (or whatever thread that created it). Now let's consider this line from your code:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
The signal readyRead() will be emitted from the current ServerThread instance (since the clientSocket object that emits it lives there), However, the receiver object is the current ServerThread instance, But that lives in the main thread. Here is what the documentation says:
If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
Now, the main point of Qt::QueuedConnection is executing the slot in the receiver object's thread. This means that, your slots ServerThread::readyRead() and ServerThread::disconnected will get executed in the main thread. This is most likely not what you meant to do, since you'll end up accessing clientSocket from the main thread. After that, any call on clientSocket that results in child QObjects being created will result in the warning you get (you can see that QTcpSocket::write() does this here).
Mixed comments of movetothread are linked mostly to usage of it to move thread object to itself.
The quote hints that the members of QThread aren't designed to be called from worker. Strictly proper way to call signal would be by using worker object model, that was shown in Qt examples and explained a few times on QT-related blogs:
class Worker : public QObject
{
Q_OBJECT
private slots:
void onTimeout()
{
qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
}
};
class Thread : public QThread
{
Q_OBJECT
private:
void run()
{
qDebug()<<"From work thread: "<<currentThreadId();
QTimer timer;
Worker worker;
connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
timer.start(1000);
exec();
}
};
worker constructed inside run() is "property" of the thread it created, so figuratively speaking, it is slaved to its context. The same effect maybe achieved if you create worker in other thread, then move it to this thread before connection was made. When you connect signal to slot of the QThread itself, you connect child thread to thread it was created by.
Use of
connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::DirectConnection);
or creating connection from your thread sometimes seems to achieve proper result, but not in this case, where you try use objects constructed in different threads together. Calling moveToThread(this) in constructor is a thing not recommended to do.
Here's the problem: let's say we have a lot of threads (>1000) receiving data via some protocol and I want to write this data in database (sql server).
For database connection, we use QSqlDatabase. According to the documentation of QSqlDatabase:
A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.
Considering we cannot create 1000 connections (which can cause performance problems), what are the options here?
What comes to mind is to create a separate thread for database writings handling.
But how to run this thread in background and wait for signals from data receiving threads? What are the other approaches that can be used in this situation?
i used a database connection as a global logger, so you might be able to adapt it to fit your needs.
the skeleton looks like:
//Logger.h
class Logger : public QObject
{
Q_OBJECT
...
public:
void log(const QString& msg):
private:
LoggerWorker* w;
QThread t;
}
// Logger.cpp
Logger::Logger(QObject* p)
:QObject(p)
{
w = new LoggerWorker;
w->moveToThread(&t);
connect(&t, SIGNAL(started()), w, SLOT(init()));
t.start();
}
...
void
Logger::log(const QString& msg)
{
QMetaObject::invokeMethod(w, "log", Q_ARG(QString, msg));
}
// LoggerWorker.h
class LoggerWorker : public QObject
{
Q_OBJECT
...
public slots:
void init()
{
// create database and connect to it
}
void log(const QString& msg)
{
// insert to database
}
private:
QSqlDatabase db;
}
note: code above might contain nuts and bugs
cheers
The best option is to have a class for working with database which resides in separate thread.You can perform all the database related operations in relevant slots. Different threads can interact with object of the class through connecting their signals to it's slots. Since the emitter and receiver exist in different threads, you will have a queued connection type. So different signals that are emitted from different threads would be queued in the database class to be processed.
I'm running a C++ program, build with Qt, that never can stop.
The program always fetches data from database and if there is a result sends an SMS.
I'm able to connect to database, but after some hours (+/- 10), it doesn't work anymore.
I don't know if the problem is because I lose connection with database or because my computer goes standby...
I'm not able in Qt to see database status: db.open() always returns true when tested inside while loop.
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("");
db.setPort();
db.setDatabaseName("");
db.setUserName("");
db.setPassword("");
if (db.open())
{
while (true)
{
// MySQL Request
// If data -> send SMS
}
}
There's always the possibility to loose a DB connection for whatever reason. You just can't rely on it. You have to check your connection inside the loop and implement some kind of re-connection scheme if the connection gets lost. As far as I know Qt doesn't do that for you.
Qt provides an event driven framework; events occur and the program reacts to those events.
When you have a never ending loop, events are queued, waiting until they can be processed. In your case, this is never going to happen, so the queue of events will just keep increasing, taking up resources such as memory.
There are two possible ways of solving this. The first is to call QApplication::processEvents every now and again in your loop.
However, the better method would be to remove the while(true) and instead use a QTimer which will periodically call a function to process any available data.
Assuming you have a class, derived from QObject, here's skeleton code using QObject's own timer
class MyObject : public QObject
{
Q_OBJECT
public:
MyObject(QObject *parent = 0);
protected:
// this will be called periodically from the timer
void timerEvent(QTimerEvent *event);
private:
m_timerId = 0; // C++ 11 initialisation
};
MyObject::MyObject(QObject *parent)
: QObject(parent)
{
m_timerId = startTimer(50); // 50-millisecond timer
}
void MyObject::timerEvent(QTimerEvent *event)
{
if(event->timerId() == m_timerId)
{
// MySQL Request
// If data -> send SMS
}
}
I have a small chat application where I use a SQLite database to store all the conversations. I've noticed that the app freezes randomly, and I then have to minimize and maximize it to make it work again. I thought that the problem might be the SQLite selects / inserts that were causing the gui to freeze. I decided to try and move all the SQLite methods into a separate thread.
After doing so the app still freezes.
Some things that might be worth knowing:
I use QTcpSocket directly in my MainWindow but it seems that there is no use in running the QTcpSocket in a separate thread?
I have separated the SQLite methods into a new thread (see implementation below)
I use 3 WebViews for displaying my chat messages, the entire application GUI is build with these WebViews
Does my code below really run in a separate thread? GUI still freezes.
My header file:
class dbThread : public QObject
{
Q_OBJECT
public:
dbThread(QObject* parent);
public slots:
bool openDB(QString agentID);
signals:
void clearPreviousHistory();
private:
QSqlDatabase db;
QHash<QString, QString> countries;
};
My cpp file:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QThread* thread = new QThread(this);
dbtrad = new dbThread(this);
dbtrad->moveToThread(thread);
dbtrad->openDB(userID);
connect(dbtrad, SIGNAL(clearPreviousHistory()), this, SLOT(clearHistoryV()));
thread->start();
}
dbThread::dbThread(QObject * parent): QObject(parent) {
}
bool dbThread::openDB(QString agentID) {
qDebug() << "OPEN DB FROM THREAD ";
// Find QSLite driver
db = QSqlDatabase::addDatabase("QSQLITE");
// ......
}
This is how I call dbThread methods from my MainWindow:
dbtrad->getHistory(channelId);
Edit
New code:
// Start database thread
QThread* thread = new QThread(this);
dbtrad = new dbThread(this);
dbtrad->moveToThread(thread);
connect(this, SIGNAL(requestOpenDB(QString)), dbtrad, SLOT(openDB(QString)));
thread->start();
emit requestOpenDB(userID);
dbtrad->openDB(userID); will execute like any normal function (Why should it?), in the GUI thread.
moveToThread allow you to execute slots called using signals in a separate thread.
If you want to execute openDB in the thread you can trigger its execution using
connect (thread, SIGNAL(started()), dbtrad, SLOT(openDBWithUIDAlreadySet()))
or
connect (this, SIGNAL(requestOpenDB(int)), dbtrad, SLOT(openDB(int)))
You need to use existing or additional signals. Qthread::start() emit the signal started(). You can also define
MainWindow{
signals:
void requestOpenDB(int);
void queryHistory(int channelid);
}
and emit the signals manually using
emit requestOpenDB(userID); //for openDB
emit queryHistory(channelId); // for getHistory
the responses from the dbThread object also need to be given using a signal which is connected to a slot. Like a notification.
QTcpSocketdoes indeed not need to be in a separated thread.
as long as all the database access is done from that thread where the database was created it should also be no problem
And now to the fun part: i think you create the database in the main thread ... by calling dbtrad->openDB(userId)
Yes so qt moveToThread() does not do what you are expecting it to do. The function that you are calling from your main thread will get executed in your main thread only. That database access is causing GUI freezes.
moveToThread only moves "event processing" in a seperate thread. Which means any slots of dbThread which are connected using Qt::QueuedConnectionwill get executed in new thread.
Following way will execute getHistory() method in your main ui thread only. You need to create a signal in main thread and make getHistory() a slot of dbThread class. Then connect both.
Reading documentation AND logs is essential!!!
In log you have a warning that YOU CAN"T MOVE TO THREAD IF OBJECT HAVE A PARENT.
Also documentation clearly says that:
Changes the thread affinity for this object and its children. The
object cannot be moved if it has a parent. Event processing will
continue in the targetThread.
Proper way to fix it:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
thread = new QThread(this);
dbtrad = new dbThread(); // NO PARENT
dbtrad->moveToThread(thread);
// run object method in thread assigned to this object:
QMetaObject::invokeMethod(dbtrad, "openDB", Qt::QueuedConnection, Q_ARG(QString, userID));
connect(dbtrad, SIGNAL(clearPreviousHistory()), this, SLOT(clearHistoryV()));
thread->start();
}
MainWindow::~MainWindow()
{
dbtrad->deleteLater();
thread->quit();
thread->wait(5000); // wait max 5 seconds to terminate thread
}