Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QObject: Cannot create children for a parent that is in a different thread. #25

Open
iamazeem opened this issue Nov 22, 2016 · 6 comments

Comments

@iamazeem
Copy link

iamazeem commented Nov 22, 2016

I've got this error for all the examples. Even for my own code for starting a simple server issued this warning. Couldn't find any issue here.

Release mode is fine but debug mode wouldn't let you run it.
Debugger shows a chain of exceptions generated here.

Assembly by the debugger:

0x77713540                   cc  int3
0x77713541  <+0x0001>        c3  ret
0x77713542  <+0x0002>        90  nop
0x77713543  <+0x0003>        90  nop
0x77713544  <+0x0004>        90  nop
0x77713545  <+0x0005>        90  nop
0x77713546  <+0x0006>        90  nop
0x77713547  <+0x0007>        90  nop

I may be wrong but it's a serious bug. I'd appreciate if you could elaborate on this.

Thanks!

@azadkuh
Copy link
Owner

azadkuh commented Nov 25, 2016

@iamazeem
I can't reproduce this error

i'm using g++ 5/6 and clang 3.8/3.9 and Qt 5.6.2 / 5.7 under Ubuntu 16.04.1 server and MacOS 10.11.6.

both Release and Debug builds are normally functional.

@iamazeem
Copy link
Author

iamazeem commented Nov 25, 2016

@azadkuh : Thank you for your response.

Well, here's the complete scenario:

Specs

- Windows 7 (32-bit) - VM
- Qt 5.7 (MinGW)
- Optimization: O3 + Os
- RTTI + exceptions are turned off

I've built QHttp separately, put the .a and .dll files with my project and tried to link it.
Now, when I run this from IDE in Debug mode, I get this error on console:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QCoreApplication(0x22fe9c), parent's thread is QThread(0x2e1ed8), current thread is QThread(0x2eef20)

And, the server doesn't accept any requests (something to do with signals).
I'm not using commondir.pri as have been used in the examples.

Another thing that I've noticed is that when I test the server (when it is running under Release), the HTTP request when partial kind-of blocks the server. The server doesn't respond. Is there any timeout for reading requests? I looked at the code and I didn't see any QNetworkAccessManager in it. Wouldn't it be more efficient if the new features are used? Just saying.

You might wanna suggest how to use QHttp as a library - the preferred way.

Thanks a lot!

~ AZEEM ~

@azadkuh
Copy link
Owner

azadkuh commented Nov 26, 2016

@iamazeem
I don't have a win machine right now, but will test it if i find some, there is no difference between release / debug mode in this regard.
as a general rule of thumb, the QObject instances are not freely movable between threads.
see here.
you have to use all QObject instances on a single thread or add a message loop to the worker threads (the reason why aQObject on a child thread won't receive any signal or message).

the qhttp server never blocks (at least by design), can you describe more or leak some code to show where you actually face a blocking call?

@iamazeem
Copy link
Author

iamazeem commented Nov 27, 2016

@azadkuh
Yes. I also do believe that there should not be any difference in different modes.
Regarding your comment about threading, if I want to run the QHttpServer with a GUI, I just have to start the QHttpServer first then run the GUI. Right?

Well, here's the minimal code example that works in Release mode and shows the error in Debug mode. The function runServer() is from one of the examples without change.

Here's the .pro file:

QT += core network
QT -= gui

CONFIG += c++11 c++14

TARGET = QhttpTest-HelloWorld
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app

SOURCES += main.cpp

win32: LIBS += -L$$PWD/../../../../qhttp/qhttp/xbin/ -lqhttp

INCLUDEPATH += $$PWD/../../../../qhttp/qhttp/src
DEPENDPATH += $$PWD/../../../../qhttp/qhttp/src

Here is the main.cpp file:

#include <QCoreApplication>
#include <QDebug>

#include "qhttpserver.hpp"
#include "qhttpserverresponse.hpp"
#include "qhttpserverrequest.hpp"

#include "qhttpclient.hpp"
#include "qhttpclientrequest.hpp"
#include "qhttpclientresponse.hpp"

void runServer(const QString& portOrPath)
{
    using namespace qhttp::server;

    qDebug() << "Running server...";

    QHttpServer server(qApp);
    // listening tcp port or Unix path
    server.listen(portOrPath, [](QHttpRequest* req, QHttpResponse* res) {
        req->collectData();

        req->onEnd([req, res](){
            res->setStatusCode(qhttp::ESTATUS_OK); // status 200
            res->addHeader("connection", "close"); // optional(default) header

            int size = req->collectedData().size();
            auto message = [size]() -> QByteArray {
                if ( size == 0 )
                    return "Hello World!\n";

                char buffer[65] = {0};
                qsnprintf(buffer, 64, "Hello!\nyou've sent me %d bytes!\n", size);
                return buffer;
            };

            res->end(message());  // reponse body data
        });

        const auto& h = req->headers();
        // optionally let the clients to shut down the server
        if ( h.keyHasValue("command", "quit") ) {
            printf("a client sends a quit command.\nserver quits.\n");
            QCoreApplication::quit();
            return;
        }

        // just for fun! print meta information:
        qDebug("\n--> %s : %s",
                qhttp::Stringify::toString(req->method()),
                qPrintable(req->url().toString().toUtf8())
              );
        qDebug("[Headers (%d)]", h.size());
        h.forEach([](auto iter) {
            qDebug(" %s : %s",
                    iter.key().constData(),
                    iter.value().constData()
                  );
        });
    });

    if ( !server.isListening() ) {
        fprintf(stderr, "failed. can not listen at port %s!\n", qPrintable(portOrPath));
        return;
    }

    qApp->exec(); // application's main event loop
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    runServer( "8080" );
    return 0;
}

Here's the output of compilation for Debug:

08:35:05: Running steps for project QhttpTest-HelloWorld...
08:35:05: Configuration unchanged, skipping qmake step.
08:35:05: Starting: "C:\Qt\Qt5.7.0\Tools\mingw530_32\bin\mingw32-make.exe" 
C:/Qt/Qt5.7.0/Tools/mingw530_32/bin/mingw32-make -f Makefile.Debug
mingw32-make[1]: Entering directory 'C:/Users/Azeem/Documents/QhttpTest-HelloWorld/build'
g++ -c -pipe -fno-keep-inline-dllexport -g -std=gnu++1y -frtti 
	-Wall -Wextra -fexceptions -mthreads 
	-DUNICODE -DQT_QML_DEBUG -DQT_NETWORK_LIB -DQT_CORE_LIB 
	-I..\..\QhttpTest-HelloWorld -I. -IC:\qhttp\qhttp\src 
	-IC:\Qt\Qt5.7.0\5.7\mingw53_32\include 
	-IC:\Qt\Qt5.7.0\5.7\mingw53_32\include\QtNetwork 
	-IC:\Qt\Qt5.7.0\5.7\mingw53_32\include\QtCore -Idebug
	-IC:\Qt\Qt5.7.0\5.7\mingw53_32\mkspecs\win32-g++  -o debug\main.o ..\main.cpp
g++ -Wl,-subsystem,console -mthreads -o debug\QhttpTest-HelloWorld.exe debug/main.o  
	-LC:\qhttp\qhttp\xbin -lqhttp 
	-LC:\Qt\Qt5.7.0\5.7\mingw53_32\lib 
	C:\Qt\Qt5.7.0\5.7\mingw53_32\lib\libQt5Networkd.a 
	C:\Qt\Qt5.7.0\5.7\mingw53_32\lib\libQt5Cored.a 
mingw32-make[1]: Leaving directory 'C:/Users/Azeem/Documents/QhttpTest-HelloWorld/build'
08:35:07: The process "C:\Qt\Qt5.7.0\Tools\mingw530_32\bin\mingw32-make.exe" exited normally.
08:35:07: Elapsed time: 00:02.

Here's the compiler output for Release:

08:34:12: Running steps for project QhttpTest-HelloWorld...
08:34:12: Configuration unchanged, skipping qmake step.
08:34:12: Starting: "C:\Qt\Qt5.7.0\Tools\mingw530_32\bin\mingw32-make.exe" 
C:/Qt/Qt5.7.0/Tools/mingw530_32/bin/mingw32-make -f Makefile.Release
mingw32-make[1]: Entering directory 'C:/Users/Azeem/Documents/build-QhttpTest-HelloWorld-Desktop_Qt_5_7_0_MinGW_32bit-Release'
g++ -c -pipe -fno-keep-inline-dllexport -O2 -std=gnu++1y -frtti 
	-Wall -Wextra -fexceptions -mthreads 
	-DUNICODE -DQT_NO_DEBUG -DQT_NETWORK_LIB -DQT_CORE_LIB 
	-I..\QhttpTest-HelloWorld -I. 
	-I..\..\..\..\qhttp\qhttp\src 
	-I..\..\..\..\Qt\Qt5.7.0\5.7\mingw53_32\include 
	-I..\..\..\..\Qt\Qt5.7.0\5.7\mingw53_32\include\QtNetwork 
	-I..\..\..\..\Qt\Qt5.7.0\5.7\mingw53_32\include\QtCore 
	-Irelease -I..\..\..\..\Qt\Qt5.7.0\5.7\mingw53_32\mkspecs\win32-g++  
	-o release\main.o ..\QhttpTest-HelloWorld\main.cpp
g++ -Wl,-s -Wl,-subsystem,console -mthreads -o release\QhttpTest-HelloWorld.exe release/main.o  
	-LC:\qhttp\qhttp\xbin -lqhttp 
	-LC:\Qt\Qt5.7.0\5.7\mingw53_32\lib 
	C:\Qt\Qt5.7.0\5.7\mingw53_32\lib\libQt5Network.a 
	C:\Qt\Qt5.7.0\5.7\mingw53_32\lib\libQt5Core.a
mingw32-make[1]: Leaving directory 'C:/Users/Azeem/Documents/build-QhttpTest-HelloWorld-Desktop_Qt_5_7_0_MinGW_32bit-Release'
08:34:14: The process "C:\Qt\Qt5.7.0\Tools\mingw530_32\bin\mingw32-make.exe" exited normally.
08:34:14: Elapsed time: 00:02.

Blocking was not for the whole server actually. It's for the request that is not well-formed.
I'm using netcat for testing the server and Chrome's postman extension. So, sending the request like this GET / HTTP/1.1\r\n\r\n would work fine. But, sending only GET\r\n\r\n or GET \r\n \ \r\n HTTP/1.1 \r\n\r\n or any of combination won't return. The server would be serving other requests just fine. What happens to the ill-formed requests? I've got Bad Request also for some requests but not for the ones I mentioned earlier. I'd like you to shed some light on this.

Regarding moving to thread, in fact, I'm not doing anything special about threading here. I was using QHttp in my project and spent a lot of time about this error. Then, I decided to validate it in isolation before embedding it in the project. So, here it is. I looked at other projects but found it quite useful and it may evolve with time and may be the first choice for writing Qt-specific restful services.

BTW, thanks a lot for writing this in the first place!
I really appreciate your help and effort in this regard!

~ AZEEM ~

@iamazeem
Copy link
Author

@azadkuh
I've tested it with GUI and the server is working fine with GUI app.
But, I've an issue that server.isListening() is not working or there is some kind of delay here.
For an existing bound port, isListening() is supposed to return false but it does not and obviously the server does not run if the port is already occupied. Any suggestion or fix?

@ivanvaccari
Copy link

ivanvaccari commented Nov 21, 2017

Don't know if is related to this kind of error but i had the same problem in debug mode.
Turn out i was using the wrong .dll, was the one produced by the release mode. I switched then to the debug .dll and now it works.
Also did a test using the debug dll in release mode and run without problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants