3

A strange behavior occured in my application when I'm using QtNetwork. I can easily create the QTcpSever and QTcpSocket instance and everything runs fine, but when it comes to QTcpSocket::write() the following error occurs:

The error

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f66980022e0), parent's thread is QThread(0x7f66a0020be0), current thread is QThread(0x7f66a0020e20)
QSocketNotifier: Can only be used with threads started with QThread

What is strange to me: I have no idea what/where this QThread(0x7f66a0020e20) is and how to get influence on it (have a look at the debugging below)

The program

I'm extending my main application (which is a library) with a network support. I put the network services into an extra class.

here the excerpt of the main application/library, where my network support is created:

QThread *thread = new QThread;
wifi = new WirelessNet(0, thread);
wifi->moveToThread(thread);
connect(thread,SIGNAL(started()), wifi,SLOT(initWifi()));
thread->start();

the network class extension:

WirelessNet::WirelessNet(QObject *parent, QThread *comThread): QTcpServer(parent)
{
     clientThread = comThread;
}

void WirelessNet::initWifi()
{
    listen(QHostAddress::Any, 5220);
    connect(this,SIGNAL(newConnection()),this,SLOT(connectionRequest()));
}

void WirelessNet::connectionRequest()
{
    client = this->nextPendingConnection();
    if(client)
        connect(client, SIGNAL(readyRead()), this, SLOT(receiveMessage()));
}

void WirelessNet:sendData(QByteArray msg)
{
if (client)
{
    qDebug()<<"FIRST "<< client->thread() << " - " << this->thread() << "\n";
    client->write(msg);
    client->waitForBytesWritten();
    qDebug()<<"LAST " << client->thread() << " - " << this->thread() << "\n";
}
}

(client and clientThread are class members: QTcpSocket*, QThread* respectively)

The debugging

Here is what the console prints out when it comes to the sendData() part:

FIRST QThread(0x7f66a0020be0) - QThread(0x7f66a0020be0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f66980022e0), parent's thread is QThread(0x7f66a0020be0), current thread is QThread(0x7f66a0020e20)
QSocketNotifier: Can only be used with threads started with QThread
LAST QThread(0x7f66a0020be0) - QThread(0x7f66a0020be0)

Concluding

In other words I have no idea on which object I should apply the moveToThread(). I already tried client->moveToThread(clientThread) aswell as this->moveToThread(clientThread). Unfortunately I don't see any additional objects to check on.

Has anyone an idea ?

user3085931
  • 1,757
  • 4
  • 29
  • 55
  • I dont understand how/where clientThread is setup. You have in the constructor `clientThread = comThread;`, but then when you create WirelessNet you pass in 0 for parent which is good, but you do not pass a second argument for the thread... : `wifi= new WirelessNet(0);`. Why do you need to pass in a thread? - you could just create one as you need it within WirelessNet (maybe have it as a member variable) e.g. `QThread *m_ClientThread` and then `m_ClientThread = new QThread;` Then you have your new thread and its all encapsulated within WirelessNet (and you can use moveToThread...). – code_fodder Mar 31 '16 at 10:54
  • @code_fodder excuse me it was a typo. I updated the top post (main application). I pass the thread so I can `moveToThread()` to the demanded parent thread. The thing is, everything (I know) is already set to the parent thread but that obscure object that I'm looking for - I hoped that it came clear with the *debugging* part of the post. – user3085931 Mar 31 '16 at 11:03
  • You don't happen to call `WirelessNet:sendData` directly from the main thread, do you? – thuga Mar 31 '16 at 11:25
  • @thuga I do. You are right I should generate an extra sending slot – user3085931 Mar 31 '16 at 11:27
  • @thuga it's working now if you make an answer I mark it as solved – user3085931 Mar 31 '16 at 11:35
  • 1
    This question doesn't include enough code to reproduce the problem, and thus is off-topic. In the future, when asking such questions, please create a *minimal*, self-contained (single `main.cpp`) test case. See e.g. [this answer](http://stackoverflow.com/a/22726559/1329652) for an example of how the code in your question should look. – Kuba hasn't forgotten Monica Mar 31 '16 at 12:27
  • 1
    Its not the issue, as thuga pointed out and answered you called a function direction from a different thread +1 to that answer, but just wanted to clear up one other thing. You pass in the thread pointer to WirelessNet of the thread that it is moved to and storing it in clientThread. You do not need to, you can access your current thread with `QThread::currentThread()` - returns `QThread *`, but what are you doing with this QThread pointer? - somehow it gives me the feeling something else may be a-miss :o – code_fodder Mar 31 '16 at 12:52
  • @code_fodder it's all clear now. My original version didn't use it anyways, I passed the `QThread *` just for debugging, so I don't mix up the threads as Qt wished. I already removed them again. – user3085931 Mar 31 '16 at 13:06

2 Answers2

3

You seem to be calling WirelessNet:sendData directly from the main thread. This causes everything inside that function to be run in the main thread as well. Your client lives in the new thread, and it is not thread-safe. It tries to create children, but current thread is different from the thread where client lives in. That is why you get that error message.

You can fix it simply by making WirelessNet:sendData a slot and call it via a signal from the main thread.

thuga
  • 12,601
  • 42
  • 52
1

My guess is that the constructor of your class is called in the calling thread, while the thread itself runs in the run() method of your class. The solution would be to initialize QTcpServer at the beginning of your run() method, so that initialization and communication through that class is done in the very same thread.

IceFire
  • 4,016
  • 2
  • 31
  • 51
  • I tried with an extra `QTcpServer*` member, initialized in `initWifi()` and moved to the `clientThread`, everything set up to this *member*-server, extended the qDebug() with that servers thread - which has now the same as everyone else - but the error is consistent – user3085931 Mar 31 '16 at 11:14
  • 1
    You can check with `QThread::currentThread()` where code is executed. I think `initWifi` is, again, called by the original thread. I would really try to put it into the start of your `run` method – IceFire Mar 31 '16 at 11:16
  • I'm not sure which `run()` you have in mind. Class `WirelessNet` inherits from `QTcpServer`, I haven't implemented a `run()` nor do I execute a `wifi->start()`. However, since initWifi is first called, when *wifi* is already moved to the new thread, nothing should be created in the old one anymore as far as I understood – user3085931 Mar 31 '16 at 11:22
  • 1
    Ok, forget about `run`. However, have you checked which thread `initWifi` is called with? You are right in that it has moved to the new thread before but some kind of thread mismatch seems to persist – IceFire Mar 31 '16 at 11:31
  • thanks for your help as thuga indicated I missed out a signal/slot communication for sending, I was calling this function directly from main. it's working now – user3085931 Mar 31 '16 at 11:36