Reading and writing QTcpSockets through different threads throws QSocketNotifier warning - c++

Basically I want to achive a simple and basic design. I have a client socket which sends and reads settings to a socket server. To avoid blocking in the main thread, the whole socket handling should be done in a diffrent thread. So I created the class MySocket:
MySocket.h (only important parts)
class MySocket : public QThread {
Q_OBJECT
public:
int port;
QHostAddress address;
bool running;
MySocket(QHostAddress addr, int port);
public slots:
void sendMessage(QByteArray data);
protected:
QTcpSocket* socket;
virtual void run();
signals:
void onDataReady(const QByteArray &data);
private slots:
void onReadyRead();
void newConnection();
void disconnected();
};
MySocket.cpp (only important parts)
#include "MySocket.h"
MySocket::MySocket(QHostAddress addr, int port) : port(port), address(addr), running(true)
{
}
void MySocket::onReadyRead()
{
QByteArray datas = socket->readAll();
//Send data to mainThread or somewhere else
emit onDataReady(datas);
}
void MySocket::run()
{
socket = new QTcpSocket();
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
QObject::connect(socket,SIGNAL(connected()),this,SLOT(newConnection()));
QObject::connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
socket->connectToHost(address, port);
while(running)
{
QApplication::processEvents();
QThread::msleep(10);
}
}
void MySocket::sendMessage(QByteArray data){
qDebug()<< "writing Data ...";
if(socket->state() == QAbstractSocket::ConnectedState)
{
std::string message(data.constData(), data.length());
qDebug() << "SendingData: " << QString::fromStdString(message);
socket->write(data);
}
else{
qDebug() << "Socket not ready for writing";
}
}
The main thread (mainwindow.cpp) just creates and starts the new thread.
mySocket = new MySocket(QHostAddress("127.0.0.1"), 3333);
controlSocket->start();
It also connects the slot and signal for writing.
connect(this, SIGNAL(write(QByteArray)), mySocket, SLOT(sendMessage(QByteArray)));
Whenever I emit the signal using emit(write("some message")); I receive the following error/notifiaciton:
QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
So first of all, how can I solve this problem? I have created a new thread and I am also using slots/signals as mentioned in many other topics facing similar problems. Is the socket still sending those messages anyway?

The object of class MySocket is a QThread, but the instance of this object itself lives in the main thread.
Only objects created in the run() function live in the other thread. So you should avoid accessing "socket" from the main thread (i.e. from the MySocket class).
2 solutions:
The easiest is to not use threads.
With threads, my advice is to create a wrapper class which encapsulate the socket (which would look very much like MySocket), with signals for dataReceived(QByteArray) and slots for sendData(QByteArray). Then, you create another class extending QThread, also with the same signal and slot and in the run() you create the wrapping class locally and connect its signals and slots to those of the class extending QThread, and then run an event loop forever (QEventLoop::exec()). Or, you can use a standard QThread class (no need to extend) and the method moveToThread() on your wrapper class. This avoids the need to create a class extending QThread.

Related

( QNativeSocketEngine) QObject: Cannot create children for a parent that is in a different thread

I'm having a problem which was ask here for a similar situation a couple of times, however I couldn't find the solution in those topics.
I'm having a main class where I'd like to extend it with a qt-network support, and this by an additional class. Let me break the source code down for you to the relevant parts:
main class
.h
class MainClass: public QObject{
Q_OBJECT
public:
[...]
private:
NetworkSupport * netSupport;
};
.cpp
MainClass::MainClass()
{
[...]
netSupport
netSupport = new NetworkSupport(this->thread());
netSupport->start();
[...]
}
network class
.h
class NetworkSupport : public QThread
{
Q_OBJECT
public:
NetworkSupport(QThread *mainThread);
~NetworkSupport();
QByteArray readData();
void sendData(QByteArray *msg);
public slots:
void acceptConnection();
void receive();
void run();
private:
QByteArray curMessage;
QThread* libThread;
QEventLoop initWlan;
protected:
QTcpServer server;
QTcpSocket* client;
};
.cpp
NetworkSupport::NetworkSupport(QThread* mainThread)
{
libThread = mainThread;
server.moveToThreaD(libThread);
server.listen(QHostAddress::Any, 5200);
QMetaObject::invokeMethode(&initWlan, "quit", Qt:QueuedConnection);
initWlan.exec();
}
void NetworkSupport::run(){
connect(&server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
}
void NetworkSupport::acceptConnection()
{
client = server.nextPendingConnection();
client->moveToThread(libThread);
if (client->state() == QAbstractSocket::ConnectedState)
connect(client, SIGNAL(readyRead()), this, SLOT(receive()));
}
void NetworkSupport::receive()
{
curMessage = client->readAll();
}
void NetworkSupport::sendData(QByteArray* msg)
{
if(client->state() == QAbstractSocket::ConnectedState)
{
client->moveToThread(libThread);
printf("Sending a message %s\n",msg->data());
client->write(*msg);
client->waitForBytesWritten();
}
}
I know I usually don't need to specifiy the moveToThread() this much, but it doesn't change a thing in the end, if all of them are there or removed.
However when executing I get the error message at client->write(*msg) in sendData(), that is:
[...]
Sending a message ?r
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QnativeSocketEngine(0x2afc660), parent's thread is QThread(0x1b59210), current thread is QThread(0x7f6a70026b60)
QSocketNotifier: Can only be used with threads started with QThread
[...]
It does look like a warning, since the the program is still in execution afterwards, but I don't receive any messages from the client (i.e. receive() gets never executed), which is I guess because of the last line from the error message.
Could it be that this error message is just misleading and if so what's it actual meaning, or did I do something completely wrong?
You are doing so many things wrong in this code that I'm not sure what to start with.
NetworkSupport::NetworkSupport(QThread* mainThread)
{
libThread = mainThread;
server.moveToThreaD(libThread);
This will do nothing. server is already in same thread as MainClass instance
server.listen(QHostAddress::Any, 5200);
Server will start to listen on same thread as MainClass
QMetaObject::invokeMethode(&initWlan, "quit", Qt:QueuedConnection);
initWlan.exec();
This mocks me a lot. This will simply start event loop and quit it almost immedietly.
}
void NetworkSupport::run(){
connect(&server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
}
This will simply run in new thread, call connect and quit thread right after connect statement - your thread will not be running anymore after connect. Also slot acceptConnection will be probably called in same thread as MainClass. I wonder when and where is MainClass created.
Seems for me like you're struggling with to many things at same time. You probably read somwhere, that you should use separate thread for network communicaton, so you won't block other threads. Try single thread approach first. When you get that working, then you should think how to utilize other thread for what you need.
Bonus question: Is this code some kind of plugin for application that may not have Qt eventloop at all? Or is it part of the full-stack Qt application?
There are a few misunderstandings in your code how Qt networking and multi threading works.
First, in Qt docs they say on QTcpServer::nextPendingConnection():
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, you must create your own Server class, that inherits from the QTcpServer, and override incomingConnection() there. In that overriden method you have to post the socket descriptor to other thread where your TCP client will live processing that connection. In this simple example we just emit a signal.
signals:
void myNewConnectionSignal(DescriptorType);
protected:
void incomingConnection(DescriptorType descriptor)
{
emit myNewConnectionSignal(descriptor);
}
Second, what is NetworkSupport thread for? I guess, you want your server object to live and work there? If so then you must rewrite it in other way. Below is the server part only. Note, that QThread already has a QEventLoop and you can use it via exec() in your run().
...
protected:
MyServer *server;
...
NetworkSupport::NetworkSupport()
{
// this is called in the main thread, so "this" lives in main thread
server=0;
client=0;
// say thread to start, but it will be actually started within run()
start();
// sometimes it is recommended to wait here for the thread started
}
NetworkSupport::~NetworkSupport()
{
// this is called in the main thread, say this thread to stop running
quit();
// wait for completion
wait();
}
void NetworkSupport::run()
{
// this is called in server thread
server=new MyServer();
if (server->listen(QHostAddress::Any, 5200))
{
// connect our new signal to slot where we create and init the TCP client, note that Qt::QueuedConnection is used because we want acceptConnection to run in the main thread
connect(server, SIGNAL(myNewConnectionSignal(DescriptorType)), MyClientsPool, SLOT(acceptConnection(DescriptorType)), Qt::QueuedConnection);
// go for infinite event loop
exec();
}
else
{
// do you always ignore errors?
}
// the thread is stopped, let's destroy the server in the thread where it was born
delete server;
server=0;
}
Client is living and working in your main thread. You must not call its methods directly from other threads. NetworkSupport lives in the main thread as well: yes, it incapsulates and manages some other thread but as an QObject itself it lives in the thread we created it in. The methods below are always executed in the main thread because we connected server's signal to NetworkSupport::acceptConnection() using Qt::QueuedConnection which says to Qt that we want the slot to be invoked in the thread where its QObject lives.
private slots:
void socketDisconnected();
...
void NetworkSupport::socketDisconnected()
{
if (client)
{
client->deleteLater();
client=0;
}
}
void NetworkSupport::acceptConnection(DescriptorType descriptor)
{
QTcpSocket* client=new QTcpSocket(this);
client->setSocketDescriptor(descriptor);
connect(client,SIGNAL(disconnected(),this,SLOT(socketDisconnected());
connect(client,SIGNAL(readyRead(),this,SLOT(receive());
}
void NetworkSupport::receive()
{
if (client)
curMessage = client->readAll();
}
void NetworkSupport::sendData(QByteArray* msg)
{
if (client)
{
client->write(*msg);
client->waitForBytesWritten();
}
}
UPDATE
If we just want to hide all network works inside the thread. Note, in the example below there is little error handling and a lot of messages data copies. You might want to optimize it for production.
// private container class incapsulated and working in the thread
class NetworkThreadContainer : public QObject
{
Q_OBJECT
public:
NetworkThreadContainer(QObject* parent=0):QObject(parent),client(0)
{
if (server.listen(QHostAddress::Any, 5200))
{
connect(&server, SIGNAL(newConnection()), this, acceptConnection());
}
else
{
// don't you want to throw exception here?
}
}
public slots:
void sendDataToClient(const QByteArray& barr)
{
if (client)
{
client->write(msg);
client->waitForBytesWritten();
}
}
void acceptConnection()
{
if (!client)
{
client = server.nextPendingConnection();
connect(client, SIGNAL(readyRead()), this, SLOT(receive()));
}
else
{
// what will you do with more than one client connections or reconnections?
}
}
void NetworkSupport::receive()
{
if (client)
{
QByteArray curMessage = client->readAll();
emit messageReceived(curMessage);
}
}
signals:
void messageReceived(const QByteArray&);
public:
QTcpClient* client;
QTcpServer server;
};
// thread class visible to outer program
class NetworkThread : public QThread
{
Q_OBJECT
public:
NetworkThread(QObject* parent=0):QObject(parent)
{
start();
}
~NetworkThread()
{
quit();
wait();
}
bool sendDataToClient(QByteArray* barr)
{
bool ok=false;
// async send data to container's thread
mutex.lock();
if (container)
{
ok=true;
QMetaObject::invokeMethod(
container,
"sendDataToClient",
Qt::QueuedConnection,
Q_ARG(QByteArray, *barr)
);
}
else
{
// container either is not ready yet or already destroyed
}
mutex.unlock();
return ok;
}
signals:
void messageReceived(const QByteArray&);
protected:
void run()
{
mutex.lock();
// I would suggest to catch exception here and assign the error result to some variable for further processing
container=new NetworkThreadContainer();
mutex.unlock();
connect(container,SIGNAL(messageReceived(QByteArray),this,SIGNAL(messageReceived(QByteArray)),Qt::QueuedConnection);
exec();
mutex.lock();
delete container;
mutex.unlock();
}
private:
QMutex mutex;
QPointer<NetworkThreadContainer> container;
};

how to use QTcpSocket in multithread?

in last question,i don't express my use-case clearly. now i describe my requirement.
in my client,i need to connect to Server with QTcpSocket.in most cases, i can write and read in gui thread(main thread).
how ever,in some time-consuming tasks,i need a single worker thread to execute task. when i connect the server in gui thread,i keep the connection all the time.
if i use a new QTcpSocket in worker thread,must i disconnect the socket in gui thread? and connect to Server again?
class Widget:public QWidget
{
Q_OBJECT
public:
Widget()
{
socket = new QTcpSocket(this);
}
private:
QHostAddress host;
unsigned int port;
QTcpSocket *socket;
private slots:
void startConnect()
{
socket->connectToHost(host,port);
}
void sendData()
{
//just send some bytes
//socket->write();
}
void doTimeConsumingTask()
{
//must i disconnect gui->socket connection before the Worker is running?
// socket->disconnectFromHost();
Worker * w = new Worker();
w->start();
}
}
class Worker:public QThread
{
Q_OBJECT
public:
Worker()
{
}
protected:
void run()
{
QTcpSocket socket;
// must i connectToHost again here ?
// do something consuming time
while(true){
//
QThread::msleep(10);
}
}
private:
QHostAddress host;
unsigned int port;
}
The easy solution to your problem is to not directly access the QTcpSocket from the worker thread. Ultimately, all you probably want to do with the socket from the worker thread is send and/or receive data to/from it. In that case, you can simply have the worker thread emit a signal with a QByteArray parameter, then connect that signal to a slot on the GUI thread that then calls write(const QByteArray& byteArray) on the QTcpSocket. Similarly, you can have your data receive function (whatever is connected to the readyRead() signal of the socket) either live in the worker thread, or live in your main thread, but upon receipt of data that the worker thread needs to process, pass it that data via a signal/slot connection.
The alternative, if you must directly access the socket (say, you need to do more than write to it, maybe you have to be able to close it or whatever), you need to wrap every use of that socket in a mutex, on both threads. This is probably best done by wrapping the raw QTcpSocket in another class that exposes only a few methods that you need, and always has a call like:
QMutexLocker locker(theMutex);
At the beginning of each function.
Is there a reason you can't pass the socket to the thread's constructor?
class Worker : public QThread{
public:
Worker(QTcpSocket* pSocket) : m_pSocket(pSocket) ...
Not sure of your use case but is there a reason you can't do this?
From the docs: http://doc.qt.io/qt-4.8/qiodevice.html
Certain subclasses of QIODevice, such as QTcpSocket and QProcess, are asynchronous. This means that I/O functions such as write() or read() always return immediately, while communication with the device itself may happen when control goes back to the event loop. QIODevice provides functions that allow you to force these operations to be performed immediately, while blocking the calling thread and without entering the event loop. This allows QIODevice subclasses to be used without an event loop, or in a separate thread:

QThread with slots and signals does not seem to create a new thread

I'm having some issues with Qt threading to allow the threaded part to update the GUI of my program. Seems like it's a known "problem" with Qt, so I found multiple tutorials, but I don't understand why my example here is not working.
I inherited from QThread as follow:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(capture_loop()));
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
this, SLOT(receivePacket(Packet*)));
}
signals:
void sendPacket(Packet*);
public slots:
void capture_loop() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit(sendPacket(packet));
std::cout << "Sending packet!" << std::endl;
}
}
};
And here is the CaptureHandler:
class CaptureHandler: public QWidget {
Q_OBJECT
public:
CaptureHandler() {
start = new QPushButton("Capture", this);
thread = new CaptureThread(this, start);
thread->start();
}
public slots:
void receivePacket(Packet *packet) {
std::cout << "Packet received!" << std::endl;
/*
Here playing with layout etc...
*/
}
private:
QPushButton *start;
CaptureThread *thread;
};
I think the signals and slots are ok, because it displays on the terminal
Sending packet!
Packet received!
Sending packet!
Packet received!
Sending packet!
Packet received!
But in the receivePacket slot, i'm trying to modify my GUI, and it does not work. The GUI just freeze, and all I can do is CTRL+C on terminal.
So i think my capture_loop, which is an infinite loop for the moment, is blocking the program, which means my thread has not started.
But I called thread->start().
I even tried to start the thread in CaptureThread constructor, by calling this->start(), but the result is the same.
Any idea?
Your using QThread wrong. By just creating the thread, it will not execute on the thread. you will need to do it inside the QThread::run function (by overriding it), since thats the only one that will run on the new thread. Please notice, that as soon as you return from this function, the thread will exit.
If you want to use your own loop inside the QThread::run function (instead using Qts default event loop), the thread won't be able to receive signals inside the run-function!
Here an example on how to use QThread:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
//calling "start" will automatically run the `run` function on the new thread
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(start()));
//use queued connection, this way the slot will be executed on the handlers thread
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
handler, SLOT(receivePacket(Packet*)), Qt::QueuedConnection);
}
signals:
void sendPacket(Packet*);
protected:
void run() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit sendPacket(packet) ;//emit is not a function
qDebug() << "Sending packet!";//you can use qDebug
}
}
};

QT: socket notifiers cannot be enabled from another thread

I have a QTcpSocket and I need to control it - write + read using multiple threads.
This works fine in QT4 but in QT5 I am getting this error and it seems that only 1 thread has access to socket at a same time. How do I make it possible for a socket to be accessed by multiple threads?
Basically I want to create 1 thread for reading and 1 thread for writing of data, so that I can asynchronously read and process the data while doing something else in rest of application.
Note: answer to Qt - Handle QTcpSocket in a new thread doesn't help here, because it describes how to transfer socket from thread 1 to thread 2 and then use it from thread 2 only. I need to use it from both threads.
You can only directly interact with the socket from one thread (the thread must have an event loop running - so you should have called exec() on it). If you want to read/write from another thread, you will need to use Signals/Slots.
Connecting a Signal emitted on one thread to a Slot of an object on another thread using the default connection type (Qt::AutoConnection) will automatically ensure a safe thread transfer occurs (using a queued connection). You can explicitly connect a Signal to a Slot using Qt::QueuedConection, but Qt::AutoConnection should work fine.
// Lives on thread 1
class MySocketOwner : public QObject
{
Q_OBJECT
public:
MySocketOwner(QObject *Parent = 0)
: QObject(Parent)
{
Socket = new QTcpSocket(this);
connect(Socket, SIGNAL(readyRead()), this, SLOT(Read()));
}
~MySocketOwner()
{
delete Socket;
}
public slots:
void Read()
{
QByteArray Data = Socket->readAll();
// Do something with the data
}
void Write(QBytrArray Data)
{
// Must always be called on thread 1
Socket->write(Data);
}
private:
QTcpSocket *Socket;
};
// Lives on thread 2
class MySocketWriter : public QObject
{
Q_OBJECT
public:
MySocketWriter(QObject *Parent = 0)
: QObject(Parent)
{
// If this is on another thread, connection will be queued
connect(this, SIGNAL(Write(QByteArray)), MySocketOwnerPointer, SLOT(Write(QBytrArray Data)));
QByteArray Data;
// Fill with data
// An event gets put onto thread 1's event queue after this
emit Write(Data);
}
signals:
void Write(QByteArray Data);
};
Like the comments on your question say, you need to think carefully about why you need this behaviour, do you really need to read the same data received by the socket on 2 separate threads?

Qt - Handle QTcpSocket in a new thread

Trying to handle a connected client socket in a new thread from global thread pool:
m_threadPool = QThreadPool::globalInstance();
void TCPListenerThread::onNewConnection()
{
QTcpSocket *clientSocket = m_tcpServer->nextPendingConnection();
clientSocket->localPort();
m_connectThread = new TCPConnectThread(clientSocket);
m_threadPool->start(m_connectThread);
}
Here's TCPConnectThread:
class TCPConnectThread : public QRunnable {
TCPConnectThread::TCPConnectThread(QTcpSocket *_socket)
{
m_socket = _socket;
this->setAutoDelete(false);
}
void TCPConnectThread::run()
{
if (! m_socket->waitForConnected(-1) )
qDebug("Failed to connect to client");
else
qDebug("Connected to %s:%d %s:%d", m_socket->localAddress(), m_socket->localPort(), m_socket->peerAddress(), m_socket->peerPort());
if (! m_socket->waitForReadyRead(-1))
qDebug("Failed to receive message from client") ;
else
qDebug("Read from client: %s", QString(m_socket->readAll()).toStdString().c_str());
if (! m_socket->waitForDisconnected(-1))
qDebug("Failed to receive disconnect message from client");
else
qDebug("Disconnected from client");
}
}
I have been getting endless errors with these. It seems cross-thread QTcpSocket handling is not feasible(See Michael's answer).
Some errors:
QSocketNotifier: socket notifiers cannot be disabled from another thread
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events t objects owned by a different thread.
Should I handle QTcpSocket in a different thread ?
What should I do if I want to handle QTcpSocket in a different thread ?
Or is there way to create a QTcpSocket from a file descriptor ?
I think this page holds your answer:
If you want to handle an incoming connection as a new QTcpSocket
object in another thread you have to pass the socketDescriptor to the
other thread and create the QTcpSocket object there and use its
setSocketDescriptor() method.
To do this, you'll have to inherit from QTcpServer and override the virtual method incomingConnection.
Within that method, create the child thread which will create a new QTcpSocket for the child socket.
For example:
class MyTcpServer : public QTcpServer
{
protected:
virtual void incomingConnection(int socketDescriptor)
{
TCPConnectThread* clientThread = new TCPConnectThread(socketDescriptor);
// add some more code to keep track of running clientThread instances...
m_threadPool->start(clientThread);
}
};
class TCPConnectThread : public QRunnable
{
private:
int m_socketDescriptor;
QScopedPointer<QTcpSocket> m_socket;
public:
TCPConnectionThread(int socketDescriptor)
: m_socketDescriptor(socketDescriptor)
{
setAutoDelete(false);
}
protected:
void TCPConnectThread::run()
{
m_socket.reset(new QTcpSocket());
m_socket->setSocketDescriptor(m_socketDescriptor);
// use m_socket
}
};
or try to use moveToThread() on the socket.