make class with QTimer in thread - qt

I need a class that sends data from another thread by timer
like this:
QPointer<Checker> checker;
connect(checker, &Checker::newData, this, &MyClass::process, Qt::BlockingQueuedConnection); // process(QMap<QString, int>)
My realization: .h
class Checker: public QObject
{
Q_OBJECT
QThread m_thread;
QTimer m_timer;
signals:
void stop();
private slots:
void started() { m_timer.start(1000); }
void stoped() { m_timer.stop(); }
void timeout();
public:
Checker();
~Checker();
Q_SIGNAL void newData(QMap<QString, int>);
};
.cpp
void Checker::timeout()
{
emit newData({});
}
Checker::Checker()
{
this->moveToThread(&m_thread);
m_timer.moveToThread(&m_thread);
m_thread.start();
connect(&m_thread, &QThread::started, this, &Checker::started);
connect(this, &Checker::stop, this, &Checker::stoped);
connect(&m_timer, &QTimer::timeout, this, &Checker::timeout);
}
Checker::~Checker()
{
emit stop();
m_thread.quit();
m_thread.wait();
}
Is this code correct?
Is there an easier way?
Why QueuedConnection don't connect? (BlockingQueuedConnection - worked)

Related

QTcpSocket handling in another QThread

I need to handle incoming tcp connections on individual QThread's.
After successful client authentication, the according socket should be stored in an QList object.
[simplified main/server-side application]
class Server : public QObject
{
Q_OBJECT
public:
Server();
private:
QList<QTcpSocket*> m_connections;
QTcpServer m_server;
void handleIncomingConnection();
void handleWaiterThread();
private slots:
void treatFinishedWaiterThread();
}
[according function definitions]
handleIncomingConnection() slot is connected with the server object's (m_server) newConnection() signal.
void Server::handleIncomingConnection()
{
QThread *waiter = new QThread();
connect(waiter, SIGNAL(started()), this, SLOT(handleWaiterThread()));
connect(waiter, SIGNAL(finished()), this, SLOT(treatFinishedWaiterThread()));
moveToThread(waiter);
waiter->start();
}
void Server::handleWaiterThread()
{
// fetch requesting socket
QTcpSocket *socket = m_server->nextPendingConnection();
// HANDLE PASSWORD AUTHENTICATION HERE ...
// IF SUCCESSFUL, CONTINUE
connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
// add to list
m_connections.append(socket);
}
void Server::treatFinishedWaiterThread()
{
QThread *caller = qobject_cast<QThread*>(sender());
caller->deleteLater();
}
If I try to run this, the threads get created but no SIGNAL is emitted when they're done, so I can't delete threads afterwards. Additionally I get this message:
QObject::moveToThread: Widgets cannot be moved to a new thread
How to fix this?
[01.06.2016]
According to QTcpServer::nextPendingConnection() it says:
The returned QTcpSocket object cannot be used from another thread. If you want to use an incoming connection from another thread, you need to override incomingConnection().
So in the end I have to create another class that inherits from QTcpServer.
[01.07.2016 #1]
I revised my code and added a custom server and waiter thread class.
[custom server class]
class CustomServer : public QTcpServer
{
Q_OBJECT
public:
WServer(QObject* = nullptr) : QTcpServer(parent) {}
signals:
void connectionRequest(qintptr);
protected:
void incomingConnection(qintptr socketDescriptor)
{
emit connectionRequest(socketDescriptor);
}
};
[custom thread class]
class Waiter : public QThread
{
Q_OBJECT
public:
Waiter(qintptr socketDescriptor, QObject *parent = nullptr)
: QThread(parent)
{
// Create socket
m_socket = new QTcpSocket(this);
m_socket->setSocketDescriptor(socketDescriptor);
}
signals:
void newSocket(QTcpSocket*);
protected:
void run()
{
// DO STUFF HERE
msleep(2500);
emit newSocket(m_socket);
}
private:
QTcpSocket *m_socket;
};
[new main class]
class ServerGUI : public QWidget
{
Q_OBJECT
public:
Server(QObject*);
private:
QList<QTcpSocket*> m_connections;
CustomServer m_server;
private slots:
void handleConnectionRequest(qintptr);
void handleNewSocket(QTcpSocket*);
}
void CustomServer::handleConnectionRequest(qintptr socketDescriptor)
{
Waiter *nextWaiter = new Waiter(socketDescriptor, this);
connect(nextWaiter, SIGNAL(newSocket(QTcpSocket*)), this, SLOT(handleNewSocket(QTcpSocket*)));
connect(nextWaiter, SIGNAL(finished()), this, SLOT(deleteLater()));
nextWaiter->start();
}
void CustomServer::handleNewSocket(QTcpSocket *socket)
{
// DO STUFF HERE ...
connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
// FINALLY ADD TO ACTIVE-CLIENT LIST ...
}
Signal & Slot specific settings:
Since CustomServer is defined as a class member (m_server) within my main widget class (that handles GUI; called ServerGUI),
connectionRequest(qintptr) signal of m_server gets connected with handleConnectionRequest(qintptr) slot of ServerGUI instance.
But now my application is crashing immediately after startup, showing following message in debug window:
HEAP[qtapp.exe]: Invalid address specified to RtlValidateHeap( 000002204F430000, 0000006E0090F4C0 )
What may be the cause of this?
[01.10.2016 #2]
I adapted my code according to user2014561's answer.
for CustomServer class
class CustomServer : public QTcpServer
{
Q_OBJECT
public:
WServer(QHostAddress, quint16, quint16, QObject* = nullptr);
~WServer();
void kickAll();
void kickClient(qintptr);
QHostAddress localAddress() const;
quint16 serverPort() const;
bool isReady() const;
bool alreadyConnected(qintptr) const;
bool clientLimitExhausted() const;
signals:
void clientConnected(qintptr);
void clientDisconnected(qintptr);
private slots:
void destroyedfunc(QObject*);
// JUST FOR TESTING PURPOSES
void waiterFinished();
private:
QList<ServerPeer*> m_connections;
quint16 m_maxAllowedClients;
bool m_readyState;
void incomingConnection(qintptr);
};
for kickAll():
void WServer::kickAll()
{
while (!m_connections.isEmpty())
{
ServerPeer *peer = m_connections.first();
QEventLoop loop;
connect(peer->thread(), SIGNAL(destroyed()), &loop, SLOT(quit())); // ### PROBLEM ENCOUNTERED HERE
QMetaObject::invokeMethod(peer, "deleteLater", Qt::QueuedConnection);
loop.exec();
}
}
for kickClient(qintptr):
void WServer::kickClient(qintptr client_id)
{
foreach (ServerPeer *peer, m_connections)
{
bool peerState;
QMetaObject::invokeMethod(peer, "hasSocket", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, peerState), Q_ARG(qintptr, client_id));
if (peerState)
{
QEventLoop loop;
connect(peer->thread(), SIGNAL(destroyed()), &loop, SLOT(quit()));
QMetaObject::invokeMethod(peer, "deleteLater", Qt::QueuedConnection);
loop.exec();
break;
}
}
}
for destroyedfunc(QObject*):
void CustomServer::destroyedfunc(QObject *obj)
{
ServerPeer *peer = static_cast<ServerPeer*>(obj);
m_connections.removeAll(peer);
}
for incomingConnection(qintptr):
void WServer::incomingConnection(qintptr handle)
{
ServerPeer *peer = new ServerPeer();
QThread *waiter = new QThread();
m_connections.append(peer); // add to list
peer->moveToThread(waiter);
// notify about client connect
connect(peer, SIGNAL(connected(qintptr)), this, SIGNAL(clientConnected(qintptr)));
// stop waiter thread by indirectly raising finished() signal
connect(peer, SIGNAL(finished()), waiter, SLOT(quit()));
// notify about client disconnect
connect(peer, SIGNAL(disconnected(qintptr)), this, SIGNAL(clientDisconnected(qintptr)));
// remove client from list
connect(peer, SIGNAL(destroyed(QObject*)), this, SLOT(destroyedfunc(QObject*)));
// notify about finished waiter thread; only for debug purposes
connect(waiter, SIGNAL(finished()), this, SLOT(waiterFinished()));
// remove waiter thread when finished
connect(waiter, SIGNAL(finished()), waiter, SLOT(deleteLater()));
QMetaObject::invokeMethod(peer, "start", Qt::QueuedConnection,
Q_ARG(qintptr, handle));
waiter->start();
}
for ServerPeer class
class ServerPeer : public QObject
{
Q_OBJECT
public:
ServerPeer(QObject* = nullptr);
~ServerPeer();
bool hasSocket(qintptr) const;
signals:
void connected(qintptr);
void disconnected(qintptr);
void finished();
public slots:
void start(qintptr);
void disconnect();
private slots :
void notifyConnect();
void notifyDisconnect();
private:
QTcpSocket *m_peer;
qintptr m_id;
};
for ServerPeer(QObject*):
ServerPeer::ServerPeer(QObject *parent) : QObject(parent), m_peer(nullptr)
{
}
for ~ServerPeer():
ServerPeer::~ServerPeer()
{
disconnect();
}
for start(qintptr):
void ServerPeer::start(qintptr handle)
{
qDebug() << "New waiter thread has been started.";
m_peer = new QTcpSocket(this);
if (!m_peer->setSocketDescriptor(handle))
{
this->deleteLater();
return;
}
if (true /*verification here*/)
{
connect(m_peer, SIGNAL(disconnected()), this, SLOT(notifyDisconnect()));
connect(m_peer, SIGNAL(disconnected()), this, SLOT(deleteLater()));
// manually do connected notification
QTimer::singleShot(0, this, SLOT(notifyConnect()));
}
else
{
this->deleteLater();
}
emit finished();
}
for disconnect():
void ServerPeer::disconnect()
{
if (m_peer != nullptr)
{
if (m_peer->state() != QAbstractSocket::SocketState::ClosingState
&& m_peer->state() != QAbstractSocket::SocketState::UnconnectedState)
m_peer->abort();
delete m_peer;
m_peer = nullptr;
}
}
for notifyConnect():
void ServerPeer::notifyConnect()
{
emit connected(m_peer);
}
for notifyDisconnect():
void ServerPeer::notifyDisconnect()
{
emit disconnected(m_peer);
}
for ServerGUI class
class ServerGUI : public QWidget
{
Q_OBJECT
public:
ServerGUI(QWidget* = nullptr);
private:
Ui::ServerWindow ui;
CustomServer *m_server;
private slots:
// For further handling, e.g. updating client view
void handleNewClient(qintptr);
void handleRemovedClient(qintptr);
}
for ServerGUI(QWidget*):
ServerGUI::ServerGUI(QWidget *parent) : QWidget(parent)
{
// initialize gui elements;
// GENERATED WITH ACCORDING *.ui FILE
ui.setupUi(this);
m_server = new WServer(QHostAddress::LocalHost, 1234, 2, this);
if (!m_server->isReady())
{
qDebug() << "Server could not start!";
delete m_server;
m_server = nullptr;
return;
}
connect(m_server, SIGNAL(clientConnected(qintptr)), this, SLOT(handleNewClient(qintptr)));
connect(m_server, SIGNAL(clientDisconnected(qintptr)), this, SLOT(handleRemovedClient(qintptr)));
}
And here my main function:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ServerGUI w;
w.show();
return a.exec();
}
With given code following message pops up if I try to kick a (selected) client:
QMetaObject::invokeMethod: No such method ServerPeer::hasSocket(qintptr)
QObject::connect: Cannot connect (null)::destroyed() to QEventLoop::quit()
How to fix this?
If I understood correctly, you want to run each peer of your server on a separate thread, if so, then the following may help you:
create a subclass of QTcpServer
reimplement incomingConnection() method
create an instance (without parent) of QThread and of ServerPeer and start the thread
do the SIGNAL - SLOT connections to remove the peer from the list and delete the thread and the peers instances
add ServerPeer to your QList
once time started, do the credentials verification; if you reject them, abort the connection
Edit, considerations:
You haven't got the connected SIGNAL because when you set a socketDescriptor to the socket was already connected, so you can simple assume after setSocketDescriptor that the socket is connected and do what you want.
About the error when closing, it's happens because you not releasing properly the threads, see my edit how can you solve that.
Finally QTcpSocket must not be accessed by diferent threads, if you need to call ServerPeer from another thread use QMetaObject::invokeMethod with QueuedConnection or BlockingQueuedConnection and SIGNAL SLOT mechanism.
Edit 2:
Now the server and it's peers will be deleted on MainWindow::closeEvent and that way you can see the disconnected function being called. I guess the problem happens depending of the order that the classes will be deleted.
You can interact with the socket including send data through it, but I believe that will be painless use the Qt methods for cross-thread calls already mentioned. In my example you can easily write to a specific peer or to all peers.
customserver.h:
//Step 1
#include <QtCore>
#include <QtNetwork>
#include "serverpeer.h"
class CustomServer : public QTcpServer
{
Q_OBJECT
public:
explicit CustomServer(const QHostAddress &host, quint16 port, quint16 maxconnections, QObject *parent = nullptr);
~CustomServer();
void kickAll();
void kickClient(qintptr id);
void writeData(const QByteArray &data, qintptr id);
void writeData(const QByteArray &data);
QHostAddress localAddress();
quint16 serverPort();
bool isReady();
signals:
void clientConnected(qintptr);
void clientDisconnected(qintptr);
private slots:
void destroyedfunc(QObject *obj);
private:
void incomingConnection(qintptr handle);
QList<ServerPeer*> m_connections;
int m_maxAllowedClients;
};
customserver.cpp:
#include "customserver.h"
CustomServer::CustomServer(const QHostAddress &host, quint16 port, quint16 maxconnections, QObject *parent) :
m_maxAllowedClients(maxconnections), QTcpServer(parent)
{
listen(host, port);
}
CustomServer::~CustomServer()
{
kickAll();
}
//Step 2
void CustomServer::incomingConnection(qintptr handle)
{
// handle client limit
if (m_connections.size() >= m_maxAllowedClients)
{
qDebug() << "Can't allow new connection: client limit reached!";
QTcpSocket *socket = new QTcpSocket();
socket->setSocketDescriptor(handle);
socket->abort();
delete socket;
return;
}
//Step 3
ServerPeer *peer = new ServerPeer();
QThread *waiter = new QThread();
peer->moveToThread(waiter);
//Step 4
connect(peer, SIGNAL(connected(qintptr)), this, SIGNAL(clientConnected(qintptr)));
connect(peer, SIGNAL(disconnected(qintptr)), this, SIGNAL(clientDisconnected(qintptr)));
connect(peer, SIGNAL(destroyed()), waiter, SLOT(quit()));
connect(peer, SIGNAL(destroyed(QObject*)), this, SLOT(destroyedfunc(QObject*)));
connect(waiter, SIGNAL(finished()), waiter, SLOT(deleteLater()));
QMetaObject::invokeMethod(peer, "start", Qt::QueuedConnection, Q_ARG(qintptr, handle));
waiter->start();
//Step 5
m_connections.append(peer);
}
void CustomServer::kickAll()
{
while (!m_connections.isEmpty())
{
ServerPeer *peer = m_connections.first();
QEventLoop loop;
connect(peer->thread(), SIGNAL(destroyed()), &loop, SLOT(quit()));
QMetaObject::invokeMethod(peer, "deleteLater", Qt::QueuedConnection);
loop.exec();
}
}
void CustomServer::kickClient(qintptr id)
{
foreach (ServerPeer *peer, m_connections)
{
ServerPeer::State hassocket;
QMetaObject::invokeMethod(peer, "hasSocket", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ServerPeer::State, hassocket), Q_ARG(qintptr, id));
if (hassocket == ServerPeer::MyTRUE)
{
QEventLoop loop;
connect(peer->thread(), SIGNAL(destroyed()), &loop, SLOT(quit()));
QMetaObject::invokeMethod(peer, "deleteLater", Qt::QueuedConnection);
loop.exec();
break;
}
}
}
void CustomServer::writeData(const QByteArray &data)
{
foreach (ServerPeer *peer, m_connections)
QMetaObject::invokeMethod(peer, "writeData", Qt::QueuedConnection, Q_ARG(QByteArray, data));
}
void CustomServer::writeData(const QByteArray &data, qintptr id)
{
foreach (ServerPeer *peer, m_connections)
{
ServerPeer::State hassocket;
QMetaObject::invokeMethod(peer, "hasSocket", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ServerPeer::State, hassocket), Q_ARG(qintptr, id));
if (hassocket == ServerPeer::MyTRUE)
{
QMetaObject::invokeMethod(peer, "writeData", Qt::QueuedConnection, Q_ARG(QByteArray, data));
break;
}
}
}
QHostAddress CustomServer::localAddress()
{
return QTcpServer::serverAddress();
}
quint16 CustomServer::serverPort()
{
return QTcpServer::serverPort();
}
bool CustomServer::isReady()
{
return QTcpServer::isListening();
}
void CustomServer::destroyedfunc(QObject *obj)
{
ServerPeer *peer = static_cast<ServerPeer*>(obj);
m_connections.removeAll(peer);
}
serverpeer.h:
#include <QtCore>
#include <QtNetwork>
class ServerPeer : public QObject
{
Q_OBJECT
public:
explicit ServerPeer(QObject *parent = nullptr);
~ServerPeer();
enum State
{
MyTRUE,
MyFALSE
};
signals:
void connected(qintptr id);
void disconnected(qintptr id);
public slots:
ServerPeer::State hasSocket(qintptr id);
void start(qintptr handle);
void writeData(const QByteArray &data);
private slots:
void readyRead();
void notifyConnect();
void notifyDisconnect();
private:
QTcpSocket *m_peer;
qintptr m_id;
};
serverpeer.cpp:
#include "serverpeer.h"
ServerPeer::ServerPeer(QObject *parent) : QObject(parent), m_peer(nullptr)
{
}
ServerPeer::~ServerPeer()
{
if (m_peer)
m_peer->abort();
}
ServerPeer::State ServerPeer::hasSocket(qintptr id)
{
if (m_id == id)
return MyTRUE;
else
return MyFALSE;
}
void ServerPeer::start(qintptr handle)
{
m_peer = new QTcpSocket(this);
m_peer->setSocketDescriptor(handle);
//Step 6
if (true /*verification here*/)
{
m_id = handle;
QTimer::singleShot(0, this, SLOT(notifyConnect()));
connect(m_peer, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(m_peer, SIGNAL(disconnected()), this, SLOT(notifyDisconnect()));
connect(m_peer, SIGNAL(disconnected()), this, SLOT(deleteLater()));
}
else
{
m_peer->abort();
this->deleteLater();
}
}
void ServerPeer::readyRead()
{
qDebug() << m_peer->readAll() << QThread::currentThread();
}
void ServerPeer::writeData(const QByteArray &data)
{
m_peer->write(data);
m_peer->flush();
}
void ServerPeer::notifyConnect()
{
emit connected(m_id);
}
void ServerPeer::notifyDisconnect()
{
emit disconnected(m_id);
}
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qRegisterMetaType<qintptr>("qintptr");
m_server = new CustomServer(QHostAddress::LocalHost, 1024, 2, this);
if (!m_server->isReady())
{
qDebug() << "Server could not start!";
delete m_server;
m_server = nullptr;
return;
}
connect(m_server, SIGNAL(clientConnected(qintptr)), this, SLOT(handleNewClient(qintptr)));
connect(m_server, SIGNAL(clientDisconnected(qintptr)), this, SLOT(handleRemovedClient(qintptr)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::closeEvent(QCloseEvent *)
{
if (m_server)
{
delete m_server;
m_server = nullptr;
}
}
void MainWindow::handleNewClient(qintptr id)
{
qDebug() << __FUNCTION__ << id;
m_server->writeData(QString("Hello client id: %0\r\n").arg(id).toLatin1(), id);
m_server->writeData(QString("New client id: %0\r\n").arg(id).toLatin1());
}
void MainWindow::handleRemovedClient(qintptr id)
{
qDebug() << __FUNCTION__ << id;
}

QProgressBar update in QThread quitting crashes

I have the following code that works as expected. It updates the progress bar value in each for loop. The only issue I have is when I'm done and call emit ProcessUserRowsFinished() in the method OnProcessUserRowsStarted the program crashes.
class UsersProcess: public QObject
{
Q_OBJECT
public:
UsersProcess(CTCore::DBConnect* db_context, UserSettingsMap user_settings_map);
void SetProgressBar(QProgressBar *progress_bar);
private:
QProgressBar *progressBar;
QSharedPointer<QList<CTCoreZen::User>> listUsers;
QScopedPointer<QThread> threadRowWorker;
signals:
void ProcessUserRowsFinished();
void ProgressBarSetValue(int value);
}
void UsersProcess::SetProgressBar(QProgressBar *progress_bar)
{
this->progressBar = progress_bar;
}
void UsersProcess::OnUserListSuccess(QList<CTCoreZen::User> *users)
{
this->listUsers.reset(users);
this->progressBar->setVisible(true);
this->progressBar->setTextVisible(true);
this->progressBar->setMinimum(0);
this->progressBar->setMaximum(this->listUsers->size());
this->progressBar->setValue(0);
this->threadRowWorker.reset(new QThread());
this->moveToThread(this->threadRowWorker.data());
connect(this->threadRowWorker.data(), &QThread::started, this, &UsersProcess::OnProcessUserRowsStarted);
connect(this, &UsersProcess::ProgressBarSetValue, this->progressBar, &QProgressBar::setValue);
connect(this, &UsersProcess::ProcessUserRowsFinished, this->threadRowWorker.data(), &QThread::quit);
connect(this, &UsersProcess::ProcessUserRowsFinished, this, &UsersProcess::deleteLater);
connect(this->threadRowWorker.data(), &QThread::finished, this->threadRowWorker.data(), &QThread::deleteLater);
this->threadRowWorker->start();
}
void UsersProcess::OnProcessUserRowsStarted()
{
int row = 0;
UsersData userData(this->dbContext);
int maxRows = this->listUsers->size();
for(auto iter = this->listUsers->begin(); iter != this->listUsers->end(); ++iter)
{
row++;
emit this->ProgressBarSetValue(row);
}
emit ProcessUserRowsFinished();
}
This is because of your thread has been deleted.
This call deletes the instance of class UsersProcess and QScopedPointer deletes the thread.
connect(this, &UsersProcess::ProcessUserRowsFinished, this, &UsersProcess::deleteLater);
But you also have this connections
connect(this, &UsersProcess::ProcessUserRowsFinished, this->threadRowWorker.data(), &QThread::quit);
connect(this->threadRowWorker.data(), &QThread::finished, this->threadRowWorker.data(), &QThread::deleteLater);
When one of this events fires the thread is already deleted.

How can I join a Thread running a function from the mainWindow class (Principal)?

I got this Error Message when I compile my project:
"Can not convert 'Principal::setValues' from type 'void*(Principal::)(void*)' to type 'void*()(void)' "
...
enter code here
void* Principal:: setValues(void*){
QString velocidadCARGA=QString::number(VelocidadCargador);
QString velocidadLAVA=QString::number(VelocidadLavado);
ui->Velocidad_Carga->setText(velocidadCARGA);
ui->Velocidad_Lavado->setText(velocidadLAVA);
ui->lbl_CantidadActual_Banda_Principal->setNum(botellasCargadas);
return NULL;
}
void Principal::on_Start_Cargador_clicked(){
pthread_t hilo3;
pthread_create(&hilo3,NULL,setValues,NULL);//error in this line.
pthread_join(hilo3,NULL);
}
Principal::setValues is a member function, so its type does not conform with a function type required by pthread_create.
To launch a member function in a thread you can declare some static method and pass this object into it:
class Principal
{
...
static void* setValuesThread(void *data);
...
}
void* Principal::setValuesThread(void *data)
{
Principal *self = reinterpret_cast<Principal*>(data);
self->setValues();
return NULL;
}
// your code
void Principal::setValues()
{
QString velocidadCARGA=QString::number(VelocidadCargador);
QString velocidadLAVA=QString::number(VelocidadLavado);
ui->Velocidad_Carga->setText(velocidadCARGA);
ui->Velocidad_Lavado->setText(velocidadLAVA);
ui->lbl_CantidadActual_Banda_Principal->setNum(botellasCargadas);
}
void Principal::on_Start_Cargador_clicked()
{
pthread_t hilo3;
pthread_create(&hilo3, NULL, Principal::setValuesThread, this);
pthread_join(hilo3,NULL);
}
But if Principal is a Qt widget (and I suppose it is), this code won't work because in Qt you can access widgets from the main thread only.
If you want to have some heavy calculations in a worker thread and then pass the results to your widget, you can use QThread and Qt signals/slots mechanism.
A simple example:
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QObject *parent = 0);
void run();
signals:
void dataReady(QString data);
}
void MyThread::run()
{
QString data = "Some data calculated in this worker thread";
emit dataReady(data);
}
class Principal
{
...
public slots:
void setData(QString data);
}
void Principal::setData(QString data)
{
ui->someLabel->setText(data);
}
void Principal::on_Start_Cargador_clicked()
{
MyThread *thread = new MyThread;
connect(thread, SIGNAL(dataReady(QString)), this, SLOT(setData(QString()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
Here is some related articles on Qt multithreading technologies:
http://doc.qt.io/qt-5/thread-basics.html
http://doc.qt.io/qt-5/threads-technologies.html

QObject::connect in QRunnable - console

I create simple multi threading server:
Create server
If new connection create new QThreadpool - QRunnable
In runnable send message to client and wait request
If client was been disconnected runnable write qDebug and runnable quit.
server.h
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
void StartServer();
protected:
void incomingConnection(int handle);
private:
QThreadPool *pool;
};
server.cpp:
#include "server.h"
Server::Server(QObject *parent) :
QTcpServer(parent)
{
pool = new QThreadPool(this);
pool->setMaxThreadCount(10);
}
void Server::StartServer()
{
this->listen(QHostAddress(dts.ipAddress),80));
}
void Server::incomingConnection(int handle)
{
Runnable *task = new Runnable();
task->setAutoDelete(true);
task->SocketDescriptor = handle;
pool->start(task);
}
runnable.h
class Runnable : public QRunnable
{
public:
Runnable();
int SocketDescriptor;
protected:
void run();
public slots:
void disconnectCln();
};
runnable.cpp
#include "runnable.h"
Runnable::Runnable()
{
}
void Runnable::run()
{
if(!SocketDescriptor) return;
QTcpSocket *newSocketCon = new QTcpSocket();
newSocketCon->setSocketDescriptor(SocketDescriptor);
!!! How make it???!!! QObgect::connect(newSocketCon, SIGNAL(disconnected()), this, SLOTS(disconnectCln()));
newSocketCon->write(mes.toUtf8().data());
newSocketCon->flush();
newSocketCon->waitForBytesWritten();
}
void Runnable::disconnectCln()
{
qDebug() << "Client was disconnect";
}
You seem to have neglected to actually ask a question, but here's the immediate problem I spot with your code: Your Runnable class does not inherit from QObject, and thus cannot have signals and slots. You will need to do that to have any hope of making it work.
class Runnable : public QObject, public QRunnable
{
Q_OBJECT
public:
Runnable();
int SocketDescriptor;
protected:
void run();
public slots:
void disconnectCln();
};
There are two important things to note here. 1) if you use multiple inheritance, QObject must come first in the list. 2) To use signals and slots you must include the Q_OBJECT macro in your class definition.

Cross thread issue in Qt4.8

I have this code:
class CMyWindow:
class CMyWindow: public QMainWindow
{ // Q_OBJECT .... here
private:
CMyServer *server;
public:
CMyWindow(QWidget *parent): QMainWindow(parent)
{
// Setup GUI here
server = new CMyServer(this);
server->startServer();
}
void thisChangeLabelCaption(QString str) {
ui.lblStatus.setText(str);
}
}
And class CMyServer:
class CMyServer: public QTcpServer
{
protected:
void incomingConnection(int sockDesc) {
/* Why below line can't be done :-| */
((CMyWindow *) parent())->thisChangeLabelCaption("New connection");
}
}
But the line in incomingConnection() rountine seem not executed.
Please tell me solution for this problem.
Update:
As #vtmarvin said, i tried this way:
class CMyWindow: public QMainWindow
{
private:
CMyServer *server;
protected slots:
void editLabel(QString str) {
thisChangeLabelCaption(str);
}
public:
CMyWindow(QWidget *parent): QMainWindow(parent) {
server = new CMyServer(this);
server->startServer();
}
void thisChangeLabelCaption(QString str) {
ui.lblStatus.setText(str);
}
}
class CMyServer: public QTcpServer
{
Q_SIGNAL:
void setText(QString str);
protected:
void incomingConnection(int sockDesc) {
/* Why below line can't be done :-| */
emit setText("New connection");
}
public:
CMyServer(QObject *parent): QTcpServer(parent)
{
connect(this, SIGNAL(setText(QString)), parent, SLOT(editLabel(QString)), Qt::QueuedConnection);
}
}
But no better result :-(
You cannot change UI from other threads than the main one - the one that owns QMainWindow. I suppose your CMyServer::incomingConnection is invoked by the QTcpServer thread. You must do a signal-slot with Qt::QueuedConnection type.

Resources