So i have 2 classes, one named ConsoleInput, which contains member function check4Flood and second named AntiFloodSys, in which connect function for signal-slot system is present, and also its signal (QTimer) and slot.
AntiFloodSys object is in check4Flood member function which scope never ends as inside there is infinite while loop. Thus the object is never destroyed. So when the object anti is created, the constuctor of AntiFloodSys class is called and therefore the connection between signal and slot.
My question at which point of the code the connection timeout signal and mySlot is separated, so the slot is never fired?
ConsoleInput cpp file looks like this:
void ConsoleInput::check4Flood(int& lineCounter)
{
AntiFloodSys anti;
while(1)
{
std::string chatLine[2];
std::cin >> chatLine[0] >> chatLine[1];
anti.input(chatLine[0], chatLine[1]);
}
}
and AntiFloodSys class like this:
AntiFloodSys::AntiFloodSys(QObject *parent) : QObject(parent)
{
timeFrame = 1000 ;
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(mySlot()));
timer->start(timeFrame);
std::cout << "AntiFloodSys constructor - timer starts " << "\n";
}
AntiFloodSys::~AntiFloodSys()
{
std::cout << "AntiFloodSys Destructor" << "\n";
}
void AntiFloodSys::input(std::string nick_, std::string line_)
{
nick = nick_;
line = line_;
std::cout << "nick: " << nick << " line: " << line << " " << "\n";
}
void AntiFloodSys::mySlot()
{
std::cout << "slot" << "\n";
}
The problem is your while(1): the Qt event loop is never processed because your program is blocked in this loop.
You can force the event loop processing calling QCoreApplication::processEvents() but the std::cin is a blocking function. So, it will not completly solve your problem.
You should move your loop in a dedicated thread that will send data to the main thread (e.g. signals/slots system).
You can also use the QSocketNotifier class to create a non blocking stdin access.
A quick example:
class Widget: public QWidget
{
Q_OBJECT
public:
Widget(): QWidget(), input(new QLabel("Edit", this))
{
connect(this, &Widget::displayText, input, &QLabel::setText);
}
private:
QLabel* input;
signals:
void displayText(QString const&);
};
class UserInput: public QObject
{
Q_OBJECT
public:
UserInput(): QObject()
{}
public slots:
void run()
{
while(1) // User Input in an infinite loop
{
std::string line;
std::cin >> line;
emit inputReceived(QString::fromStdString(line));
}
}
signals:
void inputReceived(QString const&);
};
int main(int argc, char** argv) {
QApplication app(argc, argv);
Widget* w = new Widget();
UserInput* input = new UserInput();
QThread* thread = new QThread();
input->moveToThread(thread); // Move the user input in another thread
QObject::connect(thread, &QThread::started, input, &UserInput::run);
QObject::connect(input, &UserInput::inputReceived, w, &Widget::displayText);
thread->start();
w->show();
return app.exec();
}
Related
I'm new to QT and I'm trying to create a program that shows different images depending on input from a serial interface.
I realize that there are a number of ways to achieve this and I'm looking for input from someone with experience in QT.
My idea was to send new data to a compare function that returns an integer to the main function, this integer will determine what picture will be shown. However, using a while loop results in the picture being re-drawn and not static.
My question is, should i start another thread for the image viewer, or use a different class for it?
Or is this approach hideous and should i start over?
Thankful for any input!
if(!serial.open(QIODevice::ReadOnly))
qDebug() << serial.errorString();
QObject::connect(&serial, &QSerialPort::readyRead, [&]
{
int comp=0;
int landscape =1;
int total_data = serial.bytesAvailable();
qDebug() << "New data Available: " << serial.bytesAvailable();
QByteArray datas = serial.readAll();
comp= compare(total_data,datas);
while(comp == landscape){
qDebug() << "I Picture";
QLabel label("<img src='landscape.jpg' /> ");
label.show();
}
qDebug() << datas;
});
This is the compare function that reads data from serial interface
int compare(int x, QByteArray y)
{
int r=0;
for(int i = 0; i <= x ; i++){
if (strncmp (y, "\x00",1) ==0)
{
//picture();
r=1;
return r;
}
}
return r;
}
By doing this:
while(comp == landscape){
qDebug() << "I Picture";
QLabel label("<img src='landscape.jpg' /> ");
label.show();
}
You are creating a local QLabel on the stack. It will be destroyed at each iteration.
Qt uses its own mechanism to update its objects (the event loop) and you just have to change the picture in your QLabel when needed.
So, what you can do, it's creating a QLabel in your widget and change the image in your slot:
class Window: public QWidget
{
Q_OBJECT
public:
enum ImageType {
landscape = 1,
};
Window(QObject* parent=nullptr): QWidget(parent),
myLabel(new QLabel(this))
{
if(!serial.open(QIODevice::ReadOnly))
qDebug() << serial.errorString();
connect(&serial, &QSerialPort::readyRead, this, &Window::updateImage);
}
public slots:
void updateImage()
{
int total_data = serial.bytesAvailable();
qDebug() << "New data Available: " << serial.bytesAvailable();
QByteArray datas = serial.readAll();
int const comp = compare(total_data,datas);
if (comp == Window::landscape)
myLabel->setPixmap("landscape.png");
else
myLabel->setPixmap("anotherImg.png");
qDebug() << datas;
}
private:
QLabel* myLabel;
QSerialPort serial;
};
You can use signals/slots and a thread (only if you want to do more actions during the program execution). It is very typical when using the serial line, as it is an asynchronus protocol that has to be pulled to know if there exist new data.
To do so, emit a signal every time you receive data from serial line and create a slot that process it. In this way you will use similar than an event driven system.
I have data structure where I want to wait until it recives data. When I call setInterrupt I want my thread to stop but it never returns.
This is my queue:
BufferedIpQqueue::BufferedIpQqueue()
{
}
BufferedIpQqueue::~BufferedIpQqueue()
{
bufferWaitCondition.wakeAll();
}
QString BufferedIpQqueue::get()
{
QMutexLocker locker(&mutex);
while(queue.isEmpty())
{
qDebug() << "waiting at mutex " << &mutex << "calling threadid: " << QThread::currentThreadId();
bufferWaitCondition.wait(&mutex);
}
return queue.first();
}
void BufferedIpQqueue::put(QString &data)
{
QMutexLocker locker(&mutex);
queue.append(data);
bufferWaitCondition.wakeAll();
}
void BufferedIpQqueue::wakAllThreads()
{
qDebug() << "wake all waiting threads at mutex: " << &mutex << "calling threadid: " << QThread::currentThreadId();
bufferWaitCondition.wakeAll();
}
This is my consumer thread:
IpCheckWorker::IpCheckWorker(BufferedIpQqueue *queue)
{
this->queue = queue;
interrupt = false;
}
void IpCheckWorker::setInterrupt(bool value)
{
QMutexLocker lock(&mutex);
qDebug() << "wake all threads";
interrupt = value;
queue->wakAllThreads();
}
bool IpCheckWorker::getInterruptFlag()
{
QMutexLocker lock(&mutex);
return interrupt;
}
void IpCheckWorker::process()
{
while(getInterruptFlag() == false)
{
qDebug() << "enter process loop ThreadID:" << QThread::currentThreadId();
QString check_ip = queue->get();
qDebug() << "proccess ThreadID:" << QThread::currentThreadId();
}
qDebug() << "leave process event ThreadID:" << QThread::currentThreadId();
emit finished();
}
I get the following output:
enter process loop ThreadID: 0xf94
waiting at mutex 0x51ab5f0 calling threadid: 0xf94
wake all threads
wake all waiting threads at mutex: 0x51ab5f0 calling threadid: 0x10dc
waiting at mutex 0x51ab5f0 calling threadid: 0xf94
It seems like I am stock at while(queue.isEmpty()) in my BufferedIpQqueue::get() method. Why is my mthod not returning to IpCheckWorker::process()?
Any help how to do it right would be very kind.
What you are doing is reimplementing a slightly less flexible QThreadPool. If you wish, you can look in its implementation for how it uses the wait conditions. I'd simply advise to use QThreadPool and call it a day, since it's a perfect fit for your requirements.
The thread pool maintains a queue of QRunnable instances. The instances are picked up by idle threads. The thread management is automatic. QRunnable is a lightweight class similar to QEvent - it is not a QObject.
QThreadPool is not a singleton. There is a global instance, but you don't have to use it. You can have your own instance.
This example is compatible with Qt 4.4 & up.
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QBasicTimer>
#include <QDebug>
#include <cstdlib>
class Thread : public QThread {
public:
using QThread::msleep;
};
class IpData {
QString m_value;
public:
IpData(const QString & str) : m_value(str) {}
const QString & value() const { return m_value; }
};
class IpRunnable : public QRunnable, IpData {
void run() {
qDebug() << "[" << QThread::currentThreadId()
<< "] processing ip" << value();
Thread::msleep(qrand() < (RAND_MAX/4.0) ? 0 : 100);
}
public:
IpRunnable(const IpData & data) : IpData(data) {}
IpRunnable(const QString & str) : IpData(str) {}
};
class Test : public QObject {
Q_OBJECT
int i;
QBasicTimer timer;
void timerEvent(QTimerEvent * t) {
if (t->timerId() != timer.timerId()) return;
QThreadPool::globalInstance()->start(new IpRunnable(QString::number(i)));
if (++i > 100) qApp->quit();
}
public:
Test() : i(0) { timer.start(20, this); }
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QThreadPool::globalInstance()->setMaxThreadCount(5);
Test test;
return app.exec();
}
#include "main.moc"
This example is for testing QThread. The main objective is to be able to run one time consuming blocking method in a dedicated thread and
being able to terminate and restart the thread at any point. The blocking method is a 3rd party lib which is outside our control. I know the documentation of Qt discourages using QThread::terminate but at the moment I do not see any other way.
Below is a pseduo example of the code needed to run in a dedicated thread. There is basically one method which can take 10-15 minutes to process. There is no logical place to add moveToThread to take the affinity back to main thread on QThread::termination, or executiong processEvent to handle a QThread::quit() method.
void run()
{
// initiate variables
thirdparty lib(var1, var2);
int res = lib.execute(var3, var4, var6);
// handle result and exit
}
Using Qt 4.7 on Windows 7.
Running the code produces this output
Test::doWork thread: QThread(0x219e960)
Test::started thread: QThread(0x239bce8)
Test::doTerminate thread: QThread(0x239bce8)
Test::doWork thread: QThread(0x239bce8)
QObject::moveToThread: Current thread (0x219e960) is not the object's thread (0x239bce8). Cannot move to target thread (0x239bd20)
The moveToThread API fails on the second execution of the Test::doWork() method. This appears to be because the Test instance has affinity to another thread (which is terminated at this point). How can I then change the affinity?
What is the recommended way to terminate and restart a QThread? Do I need to delete the Test instance?
The code;
#include <QCoreApplication>
#include <QThread>
#include <iostream>
#include <QDebug>
#include "Worker.h"
#include "Windows.h"
class Test : public QObject
{
Q_OBJECT
QThread* m_thread;
int m_state;
public:
Test() : m_thread(0), m_state(3) { }
public slots:
void doWork()
{
qDebug() << "Test::doWork thread:" << QObject::thread();
if (!m_thread)
{
m_thread = new QThread();
QObject::moveToThread(m_thread);
QObject::connect(m_thread, SIGNAL(started()), this, SLOT(started()));
QObject::connect(m_thread, SIGNAL(finished()), this, SLOT(finished()));
QObject::connect(m_thread, SIGNAL(terminated()), this, SLOT(terminated()));
m_thread->start();
}
}
void started()
{
qDebug() << "Test::started thread:" << QObject::thread();
Sleep(60);
}
void finished()
{
qDebug() << "Test::finished thread:" << QObject::thread();
}
void terminated()
{
qDebug() << "Test::terminated thread:" << QObject::thread();
}
void doTerminate()
{
qDebug() << "Test::doTerminate thread:" << QObject::thread();
QObject::disconnect(m_thread);
m_thread->terminate();
m_thread->wait();
m_thread = NULL;
}
int state()
{
return m_state;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
test.doWork();
Sleep(10);
test.doTerminate();
Sleep(10);
test.doWork();
return a.exec();
}
Instead of using terminate, you can call the more acceptable function quit().
I'm trying to receive some packets using a udpReceiver class that I have written using qUdpSocket in a separate QThread :
class udpThread : public QThread
{
private:
QObject * parent;
public:
udpThread(QObject * parent = 0)
{
this->parent = parent;
}
void run()
{
UdpReceiver * test = new UdpReceiver(parent);
}
};
class UdpReceiver : public QObject
{
Q_OBJECT
private:
QUdpSocket * S;
int port;
public:
UdpReceiver(QObject* parent = 0) : QObject(parent)
{
port = 9003;
initialize();
}
UdpReceiver(int p,QObject* parent = 0) : QObject(parent)
{
port = p;
initialize();
}
void initialize()
{
S = new QUdpSocket();
S->bind(port);
S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
qDebug() << "Waiting for UDP data from port " << port << " ... \n";
}
public slots:
void readPendingDiagrams()
{
while(S->waitForReadyRead())
{
QByteArray datagram;
datagram.resize(S->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
qDebug() << datagram.size() << " bytes received .... \n";
qDebug() << " bytes received .... \n";
}
}
};
And here is the main() method :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// UdpReceiver * net = new UdpReceiver();
MainWindow w;
udpThread * ut = new udpThread();
ut->start();
w.show();
return a.exec();
}
Now when I use the udpReceiver class to get the packets without the QThread it works just fine, but when I use the udpThread class it doesn't get the packets or at least the raedyread() signal does not activate some how.
When I try to get the packets without the QThread my GUI crashes somehow and the whole program hangs, that's why I want to use QThread.
I appreciate if you could help me solve this :)
Regards,
You've fallen into the same trap as many do when working with threads in Qt: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/.
It is almost always a bad idea to subclass QThread (see http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html for counterexamples).
Change your code as follows to do it the "intended" way (create a new QThread and call moveToThread on your QObject to move it to the new thread). You'll see from the output that the thread the UdpReceiver is created on is not the same as the one it receives data on, which is what you want:
#include <QApplication>
#include <QDebug>
#include <QThread>
#include <QUdpSocket>
class UdpReceiver : public QObject
{
Q_OBJECT
private:
QUdpSocket * S;
int port;
public:
UdpReceiver(QObject* parent = 0) : QObject(parent)
{
qDebug() << "Construction thread:" << QThread::currentThreadId();
port = 9003;
initialize();
}
UdpReceiver(int p,QObject* parent = 0) : QObject(parent)
{
port = p;
initialize();
}
void initialize()
{
S = new QUdpSocket();
S->bind(port);
S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
qDebug() << "Waiting for UDP data from port " << port << " ... \n";
}
public slots:
void readPendingDiagrams()
{
qDebug() << "Reading thread:" << QThread::currentThreadId();
while(S->waitForReadyRead())
{
QByteArray datagram;
datagram.resize(S->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
qDebug() << datagram.size() << " bytes received .... \n";
qDebug() << " bytes received .... \n";
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread *t = new QThread();
t->start();
UdpReceiver * net = new UdpReceiver();
net->moveToThread(t);
return a.exec();
}
#include "main.moc"
I don't have your UI code, so I don't know about any issues there. Feel free to post another question if you get stuck there and mention it in a comment and I'll try to help.
Vahid Nateghi, the init codes and the work codes must run in the same thread. But the constructor of UdpReceiver runs in the main thread against the one readPendingDiagrams runs in, that was the bug. Try this:
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QUdpSocket>
class UdpReceiver : public QObject
{
Q_OBJECT
private:
QUdpSocket * S;
int port;
public:
UdpReceiver(QObject* parent = 0) : QObject(parent)
{
qDebug() << ">HERE was the bug! thread:" << QThread::currentThreadId() << "in Construction of UdpReceiver:" << __LINE__ ;
}
public slots:
void init_thread(){
port = 10000;
qDebug() << ">thread:" << QThread::currentThreadId() << "in init_thread:" << __LINE__ ;
S = new QUdpSocket();
S->bind(port);
S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
qDebug() << "Waiting for UDP data from port " << port << " ... \n";
}
void readPendingDiagrams()
{
qDebug() << ">thread:" << QThread::currentThreadId() << "in readPendingDiagrams:" << __LINE__ ;
while(S->waitForReadyRead())
{
QByteArray datagram;
datagram.resize(S->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
qDebug() << datagram.size() << " bytes received in thread " << QThread::currentThreadId() << "in readPendingDiagrams:" << __LINE__ ;
}
}
};
int main(int argc, char *argv[])
{
qDebug() << ">Main thread:" << QThread::currentThreadId() << "in main:" << __LINE__ ;
QCoreApplication a(argc, argv);
QThread *t = new QThread();
UdpReceiver * net = new UdpReceiver();
net->moveToThread(t);
net->connect(t,SIGNAL(started()),net,SLOT(init_thread()));
t->start();
return a.exec();
}
#include "main.moc"
I've created my own TestService which runs on a separate QThread, but when the MainLoop terminates the QThread::finished signal does not get emitted. I saw a similar question, but the problem was slightly different there because the OP was overloading QThread whereas I simply move my class to the thread.
Note that I do not overload the QThread class, I only overload QObject based on this example: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Here is my TestService class:
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <iostream>
using namespace std;
class TestService: public QObject
{
Q_OBJECT;
private:
volatile int _count;
QWaitCondition _monitor;
QMutex _mutex;
QThread* _thread;
public:
TestService(int numSeconds)
{
_count = numSeconds;
_thread = NULL;
cout << "TestService()" << endl;
}
virtual ~TestService()
{
cout << "~TestService()" << endl;
}
void Start()
{
QMutexLocker locker(&_mutex);
if(_thread == NULL)
{
_thread = new QThread;
// Move this service to a new thread
this->moveToThread(_thread);
// The main loop will be executed when the thread
// signals that it has started.
connect(_thread, SIGNAL(started()), this, SLOT(MainLoop()));
// Make sure that we notify ourselves when the thread
// is finished in order to correctly clean-up the thread.
connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished()));
// The thread will quit when the sercives
// signals that it's finished.
connect(this, SIGNAL(Finished()), _thread, SLOT(quit()));
// The thread will be scheduled for deletion when the
// service signals that it's finished
connect(this, SIGNAL(Finished()), _thread, SLOT(deleteLater()));
// Start the thread
_thread->start();
}
}
void Stop()
{
_count = 0;
_monitor.wakeAll();
}
private slots:
void MainLoop()
{
cout << "MainLoop() Entered" << endl;
while(_count > 0)
{
cout << "T minus " << _count << " seconds." << endl;
QMutexLocker locker(&_mutex);
_monitor.wait(&_mutex, 1000);
_count--;
}
cout << "MainLoop() Finished" << endl;
emit Finished();
}
virtual void OnFinished()
{
cout << "OnFinished()" << endl;
}
signals:
void Finished();
};
Here is the testing code:
void ServiceTest()
{
cout << "Press q to quit." << endl;
cout << "Press s to start." << endl;
cout << "Press t to stop." << endl;
QSharedPointer<TestService> testService(new TestService(10));
char in = 'a';
while( in != 'q' )
{
switch(tolower(in))
{
case 's':
testService->Start();
break;
case 't':
testService->Stop();
break;
default:
break;
}
cin.get(in);
in = tolower(in);
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ServiceTest();
QTimer::singleShot(0, &a, SLOT(quit()));
return a.exec();
}
The output is:
Press q to quit.
Press s to start.
Press t to stop.
TestService()
s
MainLoop() Entered
T minus 10 seconds.
T minus 9 seconds.
T minus 8 seconds.
t
MainLoop() Finished
q
~TestService()
Press any key to continue . . .
Could anybody explain why is finished not being emitted how I can fix it?
Signal finished() gets emitted of cause, but you don't catch it.
Here:
connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished()));
Qt::QueuedConnection is used, as _thread and this (service) are in different threads.
By the time finished() is emitted, _thread's event loop already finished executing, so signal will not be delivered to the slot.
You can explicitly use Qt::DirectConnection.
EDIT:
QTherad works like this:
QThread::start()
{
emit started();
run();
emit finished();
}
QThread::run()
{
eventloop->exec();
}
So, by the time finished is emitted, eventloop already stop execution. And as you move service to _thread, service's event loop is _thread event loop.
Note, that QObject itself has no its own event loop. Event loops are created by dialogs, threads and application.
Actually I will recommend in your simple case just use QtConcurent::run, as you do not perform actual event processing in the new thread, but just run single function.