QTimer in a thread - multithreading

I just merely want to emit 2 signal and a Qtimer timeout on button click from a GUI.
Although 2 SIGNAL/SLOT WORKS the QTimer's SIGNAL/SLOT is not working, the whentimeout SLOT never works.
There is no error even.
GUI(DIALOG.CPP)
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
fduthread = new fdustatus(this);
connect(fduthread,SIGNAL(NumberChanged(int)),this,SLOT(onNumberChanged(int)));
connect(fduthread,SIGNAL(nameChange(QString)),this,SLOT(onNameChanged(QString)));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::onNumberChanged(int number)
{
ui->label->setText(QString::number(number));
}
void Dialog::onNameChanged(QString s)
{
ui->label_2->setText(s);
}
void Dialog::on_pushButton_clicked()
{
fduthread->start();
fduthread->stop=false;
}
void Dialog::on_pushButton_2_clicked()
{
ui->label_2->setText("");
fduthread->stop=true;
}
THAT IS MY THREAD
#include "fdustatus.h"
#include<QMutex>
#include<QTimer>
#include<QDebug>
fdustatus::fdustatus(QObject *parent):QThread(parent)
{
}
void fdustatus::run()
{
mytimer = new QTimer();
mytimer->setInterval(10);
connect( mytimer,SIGNAL(timeout()),this,SLOT(whentimeout()));
mytimer->start();
for(int i =0;i<100;i++)
{
QMutex mutex;
mutex.lock();
if(this->stop)break;
mutex.unlock();
emit NumberChanged(i*10);
emit nameChange(getstring());
this->msleep(100);
}
}
QString fdustatus::getstring()
{
QString networkport;
networkport.append("Alarm Active");
return networkport;
}
void fdustatus::whentimeout()
{
qDebug() << "timer ended from thread..";
}

Related

How to launch an std::async thread from within an std::async thread and let the first one die once the second is launched?

What I am trying to achieve is having and autonomous async thread mill, were async A does its task, launches async B and dies. async B does the same in repeat.
Example code: main.cpp
class operation_manager : public std::enable_shared_from_this<operation_manager> {
public:
operation_manager() {}
void do_operation(void) {
std::function<void(std::shared_ptr<operation_manager>)> fun( [this](std::shared_ptr<operation_manager> a_ptr) {
if( a_ptr != nullptr ) {
a_ptr->do_print();
}
} );
i_ap.read(fun, shared_from_this());
}
void do_print(void) {
std::cout << "Hello world\n" << std::flush;
do_operation();
}
private:
async_operation i_ap;
};
int main(int argc, const char * argv[]) {
auto om( std::make_shared<operation_manager>() );
om->do_operation();
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
Example code: async_operation.hpp
class async_operation {
public:
async_operation() {};
template<typename T>
void read(std::function<void(std::shared_ptr<T>)> a_callback, std::shared_ptr<T> a_ptr) {
auto result( std::async(std::launch::async, [&]() {
wait();
a_callback(a_ptr);
return true;
}) );
result.get();
}
private:
void wait(void) const {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
};
Your mistake is calling result.get() inside the async task - that causes it to block and wait for the next task to finish. wait you need to do is save the futures somewhere, and let them run.
Here is the modified code to the async_operation class:
std::vector<std::shared_ptr<std::future<bool>>> results;
class async_operation {
public:
async_operation() {};
template<typename T>
void read(std::function<void(std::shared_ptr<T>)> a_callback, std::shared_ptr<T> a_ptr) {
results.push_back(std::make_shared<std::future<bool>>(std::async(std::launch::async, [=]() {
wait();
a_callback(a_ptr);
return true;
})));
}
private:
void wait(void) const {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
};

cannot handle QNetworkAccessManager::finised signal in multithreading

I want to serialize network requests using QNetworkAccessManager. For achieving it i wrote such class:
#ifndef CLIENT_H
#define CLIENT_H
#include <queue>
#include <mutex>
#include <condition_variable>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
class Client : public QObject
{
Q_OBJECT
struct RequestRecord
{
RequestRecord(QString u, int o):url(u),operation(o){}
QString url;
int operation;
};
std::mutex mutex;
std::queue<RequestRecord*> requests;
QNetworkAccessManager *manager;
bool running;
std::condition_variable cv;
public:
Client():manager(nullptr){}
~Client()
{
if(manager)
delete manager;
}
void request_cppreference()
{
std::unique_lock<std::mutex> lock(mutex);
requests.push(new RequestRecord("http://en.cppreference.com",0));
cv.notify_one();
}
void request_qt()
{
std::unique_lock<std::mutex> lock(mutex);
requests.push(new RequestRecord("http://doc.qt.io/qt-5/qnetworkaccessmanager.html",1));
cv.notify_one();
}
void process()
{
manager = new QNetworkAccessManager;
connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
{
std::unique_lock<std::mutex> lock(mutex);
RequestRecord *front = requests.front();
requests.pop();
delete front;
reply->deleteLater();
});
running = true;
while (running)
{
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock);
RequestRecord *front = requests.front();
manager->get(QNetworkRequest(QUrl(front->url)));
}
}
};
#endif // CLIENT_H
As one can see, there are 2 methods for requesting data from network and method process, which should be called in separate thread.
I'm using this class as follows:
Client *client = new Client;
std::thread thr([client](){
client->process();
});
std::this_thread::sleep_for(std::chrono::seconds(1));
client->request_qt();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
client->request_cppreference();
This example illustrate 2 consecutive requests to network from one thread and processing of these request in another. All works fine except my lambda is never called. Requests are sent (checked it using wireshark), but i cannot get replies. What is the cause?
as #thuga suppose the problem was in event loop. My thread always waiting on cv and thus cannot process events, little hack solve the problem:
void process()
{
manager = new QNetworkAccessManager;
connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
{
std::unique_lock<std::mutex> lock(mutex);
RequestRecord *front = requests.front();
requests.pop();
delete front;
qDebug() << reply->readAll();
processed = true;
reply->deleteLater();
});
running = true;
while (running)
{
{
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock);
if(requests.size() > 0 && processed)
{
RequestRecord *front = requests.front();
manager->get(QNetworkRequest(QUrl(front->url)));
processed = false;
QtConcurrent::run([this]()
{
while (running)
{
cv.notify_one();
msleep(10);
}
});
}
}
QCoreApplication::processEvents();
}
}
};
it's not beautiful obvious since it is using 3 threads instead of 2, but it is Qt with this perfect phrase:
QUrl QNetworkReply::url() const Returns the URL of the content
downloaded or uploaded. Note that the URL may be different from that
of the original request. If the
QNetworkRequest::FollowRedirectsAttribute was set in the request, then
this function returns the current url that the network API is
accessing, i.e the url emitted in the QNetworkReply::redirected
signal.

SFML Thread does not works for window

I have simple code:
#include <SFML\Graphics.hpp>
sf::RenderWindow *mainWindow;
void changeMainWindowParameters()
{
while(mainWindow->isOpen())
{
sf::Event event;
while (mainWindow->pollEvent(event))
{
if(event.type == sf::Event::Closed)
{
mainWindow->close();
return;
}
}
mainWindow->clear();
mainWindow->draw(sf::CircleShape(50.0F, 30));
mainWindow->display();
}
}
int main()
{
mainWindow = new sf::RenderWindow(
sf::VideoMode(100, 100), "Window");
changeMainWindowParameters();
}
But if I want to do it with threads, it does not work as in previous example:
#include <SFML\Graphics.hpp>
sf::RenderWindow *mainWindow;
void changeMainWindowParameters()
{
while(mainWindow->isOpen())
{
sf::Event event;
while (mainWindow->pollEvent(event))
{
if(event.type == sf::Event::Closed)
{
mainWindow->close();
return;
}
}
mainWindow->clear();
mainWindow->draw(sf::CircleShape(50.0F, 30));
mainWindow->display();
}
}
int main()
{
mainWindow = new sf::RenderWindow(
sf::VideoMode(100, 100), "Window");
sf::Thread th(changeMainWindowParameters);
th.launch();
//code
th.wait();
}
I can't close the window/move it etc.
I want the program to do something (drawing images on this window etc.) and so I could close/move this window.
Where is wrong?
I solve this problem:
#include <SFML\Graphics.hpp>
#include <thread>
#include <iostream>
sf::RenderWindow *mainWindow = nullptr;
void changeMainWindowParameters()
{
if (mainWindow == nullptr)
mainWindow = new sf::RenderWindow(sf::VideoMode(100, 100), "Window");
while(mainWindow->isOpen())
{
sf::Event event;
while (mainWindow->pollEvent(event))
{
if(event.type == sf::Event::Closed)
{
mainWindow->close();
return;
}
}
mainWindow->clear();
mainWindow->draw(sf::CircleShape(50.0F, 30));
mainWindow->display();
}
}
int main()
{
sf::Thread th(changeMainWindowParameters);
th.launch();
for(;;)
std::cout << '.';
th.wait();
}
We must remember that the event loop (more precisely, the pollEvent or waitEvent function) must be called in the same thread that created the window.

Write to QTcpSocket fails with different thread error

I have created a simple threaded TCP server which collects 3 lines read from the socket, and then tries to echo them back to the socket. The function echoCommand below crashes.
#include "fortunethread.h"
#include <QtNetwork>
#include <QDataStream>
FortuneThread::FortuneThread(int socketDescriptor, QObject *parent)
: QThread(parent), socketDescriptor(socketDescriptor), in(0)
{
}
void FortuneThread::run()
{
tcpSocketPtr = new QTcpSocket;
if (!tcpSocketPtr->setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocketPtr->error());
return;
}
in = new QDataStream(tcpSocketPtr);
connect(tcpSocketPtr, SIGNAL(readyRead()), this, SLOT(readCommand()) );
QThread::exec();
}
void FortuneThread::echoCommand()
{
QString block;
QTextStream out(&block, QIODevice::WriteOnly);
for (QStringList::Iterator it = commandList.begin(); it != commandList.end(); ++it) {
out << "Command: " << *it << endl;
}
out << endl;
tcpSocketPtr->write(block.toUtf8());
tcpSocketPtr->disconnectFromHost();
tcpSocketPtr->waitForDisconnected();
}
void FortuneThread::readCommand()
{
while (tcpSocketPtr->canReadLine())
{
commandList << (tcpSocketPtr->readLine()).trimmed();
}
if (commandList.size() > 2)
{
echoCommand();
}
}
and here is the file where I connect up the slots/signals:
#include "fortuneserver.h"
#include "fortunethread.h"
#include <stdlib.h>
FortuneServer::FortuneServer(QObject *parent)
: QTcpServer(parent)
{
}
void FortuneServer::incomingConnection(qintptr socketDescriptor)
{
QString fortune = fortunes.at(qrand() % fortunes.size());
FortuneThread *thread = new FortuneThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
during or after the socket write, with this error:
**QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f19cc002720), parent's thread is FortuneThread(0x25411d0), current thread is QThread(0x220ff90)**
Since I create the tcpSocketPtr in the run() function, I know it is in the same thread as this function. Why would the socket write fail? I should point out that the write is succeeding since I see the output on the telnet window...but still the socket write fails...
Just more info...I found that I should NOT put a slot in a QThread..not sure how to get around this, but here is my class definiation:
class FortuneThread : public QThread
{
Q_OBJECT
public:
FortuneThread(int socketDescriptor, QObject *parent);
void run();
signals:
void error(QTcpSocket::SocketError socketError);
private slots:
void readCommand();
private:
void echoCommand();
int socketDescriptor;
QDataStream *in;
QStringList commandList;
QTcpSocket *tcpSocketPtr;
};

Qt MainWindow is not updating

I am using Qt to generate a Window. Additionally I use libnfc to get access to a nfc reader, so far so good.
In my self written nfc-class i generate a new thread, this thread is polling for new tags on the reader. If there is a new tag, the thread will start a signal event for the MainWindow.
In the main window I have just a QWebView which will show different websites on different states (after start, new tag, tag removed), just realy basic stuff.
My problem is now: that the main window (or the QWebView) is not updating. If i switch to another programm and go back to my app, the window will be updated. I was already searching with google and trying different stuff but nothing helps.
Here the thread code:
class NFC_Thread : public QThread
{
Q_OBJECT
public:
NFC_Thread(NFC_Reader * Reader);
void run();
signals:
void NewTarget(nfc_target Target);
void TargetRemoved(nfc_target Target);
private:
int mError;
bool mStopPolling;
};
void NFC_Thread::run()
{
mError = 0;
mStopPolling = false;
while(!mStopPolling)
{
nfc_target Target;
mError = nfc_initiator_poll_target(mReader->GetDevice(), nmModulations, szModulations, mPollNr, mPollPeriod, &Target);
if(mError > 0)
{
cout << "NFC: found target" << endl;
}
#warning Bug in driver: Timeout generate a NFC_EIO Error, 'https://code.google.com/p/libnfc/issues/detail?id=224'
else if(mError > 0)
{
cout << "NFC: Error" << endl;
mStopPolling = true;
}
else
{
cout << "NFC: no target found" << endl;
}
}
}
MainWindow Code:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void SetNewTarget(nfc_target Target);
void doTargetRemoved(nfc_target Target);
private:
bool event(QEvent *event);
void resizeEvent(QResizeEvent *);
void adjust();
Ui::MainWindow *ui;
QWebView * mWebView;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mWebView = new QWebView(this);
mWebView->load(QUrl("http://www.pbuchegger.at/"));
mWebView->show();
}
void MainWindow::SetNewTarget(nfc_target Target)
{
QString str = "NEW TARGET: \n";
{
char * s;
str_nfc_target(&s, Target, false);
str += s;
delete s;
}
//cout << "NFC: Target: " << str << endl;
mWebView->load(QUrl("http://www.google.at"));
update();
repaint();
mWebView->update();
qApp->processEvents();
/*QMessageBox msgBox;
msgBox.setText(str);
msgBox.exec();*/
}
void MainWindow::doTargetRemoved(nfc_target Target)
{
QString str = "TARGET REMOVED: \n";
{
char * s;
str_nfc_target(&s, Target, false);
str += s;
delete s;
}
//cout << "NFC: Target: " << str << endl;
mWebView->load(QUrl("http://www.cde.at"));
update();
repaint();
mWebView->update();
qApp->processEvents();
/*QMessageBox msgBox;
msgBox.setText(str);
msgBox.exec();*/
}
bool MainWindow::event(QEvent *event)
{
if(event->type() == QEvent::Resize)
{
adjust();
return true;
}
return false;
}
void MainWindow::resizeEvent(QResizeEvent *)
{
adjust();
}
void MainWindow::adjust()
{
mWebView->setGeometry(0, 0, ui->centralWidget->geometry().width(), ui->centralWidget->geometry().height());
}
main code:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qRegisterMetaType<nfc_target>("nfc_target");
MainWindow w;
w.setWindowState(Qt::WindowMaximized);
NFC_Reader Reader;
nfc_device_string devs;
size_t nr;
QString str = "";
Reader.GetDevices(devs, nr);
if(nr > 0)
{
if(!Reader.InitReader(NULL))
{
str += "Error on init!";
}
else
{
Reader.Start_Polling();
str += "Started Polling!";
}
}
else
{
str += "No Device found!";
}
w.SetText(str);
SignalHelper Helper;
QObject::connect(Reader.GetThread(), SIGNAL(NewTarget(nfc_target)), &Helper, SLOT(doNewTarget(nfc_target)));
QObject::connect(Reader.GetThread(), SIGNAL(TargetRemoved(nfc_target)), &Helper, SLOT(doTargetRemoved(nfc_target)));
QObject::connect(&Helper, SIGNAL(NewTarget(nfc_target)), &w, SLOT(SetNewTarget(nfc_target)));
QObject::connect(&Helper, SIGNAL(TargetRemoved(nfc_target)), &w, SLOT(doTargetRemoved(nfc_target)));
w.show();
int ret = a.exec();
Reader.Abort_Polling();
return ret;
}
As u can see, I have a "Helper" class, this class is just getting the signal in a slot and starting again a signal which will be forward to the mainwindow. If i want to forward the signal directly to the mainwindow, nothing is happening (like the signal is not fired), but i was checking it with the Qt-About box, and the box is showing up.
Helper class:
class SignalHelper : public QObject
{
Q_OBJECT
public slots:
void doNewTarget(nfc_target Target);
void doTargetRemoved(nfc_target Target);
signals:
void NewTarget(nfc_target Target);
void TargetRemoved(nfc_target Target);
};
void SignalHelper::doNewTarget(nfc_target Target)
{
emit NewTarget(Target);
}
void SignalHelper::doTargetRemoved(nfc_target Target)
{
emit TargetRemoved(Target);
}
no compiler errors or linker errors. this code shows just the important stuff, all the unimportant stuff is removed. just for your information the project file:
QT += core gui testlib
QT += webkit
greaterThan(QT_MAJOR_VERSION, 4) {
QT += widgets
}
TARGET = NFC_GUI
TEMPLATE = app
SOURCES += main.cpp \
mainwindow.cpp \
nfc_thread.cpp \
nfc_reader.cpp \
signal_helper.cpp
HEADERS += mainwindow.h nfc_thread.h nfc_reader.h signal_helper.h
FORMS += mainwindow.ui
LIBS += -lnfc
Making my comment an answer:
Your function
bool MainWindow::event(QEvent *event)
{
if(event->type() == QEvent::Resize)
{
adjust();
return true;
}
return false;
}
eats any event which is handled in QMainWindow except for QEvent::Resize. You need to call the default behaviour for events you are not interested in:
bool MainWindow::event(QEvent *event)
{
if(event->type() == QEvent::Resize)
{
adjust();
return true;
}
// call the parent implementation
return QMainWindow::event(event);
}
Note you can also just simply implement QWidget::resizeEvent:
void MainWindow::resizeEvent(QResizeEvent *event)
{
adjust();
QMainWindow::resizeEvent(event);
}
If you're calling slots from signals between different threads, you need to make the connect calls with Qt::QueuedConnection as the Connection Type.

Resources