1

I built a server in Qt that takes every client that connects to it and sends the connection away to worker thread (I implement this with QRunnable and I connect the thread to QThreadPool).

In my thread I read without a problem from the socket (QTcpSocket socket ) but when I try to write to it I get the following error:

QObject: Can not create children for a parent that is in a different thread. The parent thread is QThread (0x28602f90860)

I tried to fix this by adding the code line:

socket->setParent(this);

In the constructor of my thread - but it did not help, I got the following error:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x1dab6331c60), parent's thread is QThread(0x1dab62eacf0), current thread is QThread(0x1dab632b140)
QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

Does anyone know what this problem is or how to solve it?

A sparse example of the relevant code snippets:

class myTask  : public QObject , public QRunnable, public parser
{
     Q_OBJECT

public:
    myTask(QTcpSocket *s)
    {
        socket = s;
        socket->setParent(this);
        // if i do here socket->write("hello world"); it's work , but not in run()
    }

signals:
    void Result(int num);

protected:
    void run()
    {
        socket->write("hello world"); // i get here the error
    }

private:
    QTcpSocket *socket;
};


/* the creation of the worknig thread and the tcp client creation */
void MyClient::readyRead()
{

     myTask * mtask = new myTask(socket);
     mtask->setAutoDelete(true);

     // connect result to our loacal result function
     connect(mtask, SIGNAL(Result(int)), this, SLOT(taskResults(int)), Qt::QueuedConnection);

     //start havy job
     QThreadPool::globalInstance()->start(mtask);
}

void MyClient::SetSocket(int descriptor)
{
    socket = new QTcpSocket(this);

    connect(socket, SIGNAL(connected()), this, SLOT(connected()));
    connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
    connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));


    socket->setSocketDescriptor(descriptor);
    qDebug() <<"[*] client connected";

}

class MyClient : public QObject
{
    Q_OBJECT
public:
    explicit MyClient(QObject *parent = nullptr);
    void SetSocket(int descriptor);

signals:


public slots:
    void connected();
    void disconnected();
    void readyRead();
    void taskResults(int num);

private:
    QTcpSocket *socket;
};
ymoreau
  • 3,402
  • 1
  • 22
  • 60
YOKO
  • 119
  • 1
  • 7
  • Of course the problem has likely to do with something else and not QRunnable which is just about spawning non-blocking task. Of course you can work with QTcpSocket in non-blocking manner without the "task". I would start with that and stripping of example of unnecessary details usually helps. And if that works then the problem is with *the way QRunnable used* and *not* with the socket. – Alexander V Jan 18 '18 at 21:52
  • if u try to send from `myTak constructor` it's works fine , only from the minit i get into `run()` i start to get errors – YOKO Jan 18 '18 at 22:07
  • What is the "heavy job"? As @AlexanderVX, Qt's network module is asynchronous and designed to be used in the main thread, so you shouldn't need to move any of the network I/O itself to another thread. Also, you can't move objects to a thread in which their parent does not live, nor should you be calling the socket's `read()` or `write()` functions from a thread in which the socket doesn't live. – bnaecker Jan 18 '18 at 22:38
  • `heavy job` is take from the network files make some monipulation on this and write them back to the client , i do it in a seperate runable because i want a real multy threading and avoid ANY blocking acticity - it's supposed to be fully functional real server. – YOKO Jan 19 '18 at 07:14
  • @YOKO I suggest you start by reading Qt documentation about threads and QObject. This will help you to understand what you can and cannot do when playing with QObject accross threads: http://doc.qt.io/qt-5/threads-qobject.html – Benjamin T Jan 19 '18 at 16:03
  • @YOKO, you already have a solution as you said ... _"send from myTask constructor it's works fine"_. So class `myTask` owns run() and thats the thread socket goes with .. try to make `MyClient` class inherit `myTask` so that you don't create explicit myTask object .. – Mohammad Kanan Jan 19 '18 at 17:01
  • I eventually fix this issues with `emit` and signals at `my_task` to `MyClient` for writing, ready read and ready write , i think this a clever way to combine asinc actions with multythreading (but if i rung i will be happy if someone currect me) – YOKO Jan 20 '18 at 19:42

1 Answers1

0

If you look at QTcpServer documentation one of the notes says:

Note: 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 that there's also a note on incomingConnection():

Note: 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 subclass QTcpServer class and implement an incomingConnection() that gets the socket descriptor and send to the thread.

Here an example of a threaded QTcpServer.

Taylor Wood
  • 15,886
  • 1
  • 20
  • 37