2016-03-17 11 views
5

Abbiamo un'applicazione OS X C++, che utilizza Qt 5.5 che fornisce un'interfaccia server HTTP semplice. È essenzialmente simile all'esempio Fortune server fornito da Qt (http://doc.qt.io/qt-5/qtnetwork-fortuneserver-example.html), ma ciò che vediamo è che a volte l'applicazione è seg faulting alla chiusura, con la seguente analisi di stack (filetto 6 crash):Come prevenire le condizioni di gara di arresto con classi Qt Network

Thread 0:: Dispatch queue: com.apple.main-thread 
0 libsystem_kernel.dylib   0x00007fff8deb4fca __open + 10 

Thread 1:: Dispatch queue: com.apple.libdispatch-manager 
0 libsystem_kernel.dylib   0x00007fff8deb6232 kevent64 + 10 
1 libdispatch.dylib    0x00007fff90f0426e _dispatch_mgr_thread + 52 

Thread 2: 
0 libsystem_kernel.dylib   0x00007fff8deb594a __workq_kernreturn + 10 
1 libsystem_pthread.dylib   0x00007fff887833dd start_wqthread + 13 

Thread 3: 
0 libsystem_kernel.dylib   0x00007fff8deb594a __workq_kernreturn + 10 
1 libsystem_pthread.dylib   0x00007fff887833dd start_wqthread + 13 

Thread 4: 
0 libsystem_kernel.dylib   0x00007fff8deb594a __workq_kernreturn + 10 
1 libsystem_pthread.dylib   0x00007fff887833dd start_wqthread + 13 

Thread 5:: Dispatch queue: com.apple.NSXPCConnection.m-user.com.apple.airportd 
0 libsystem_platform.dylib  0x00007fff8923378d _os_lock_handoff_lock + 23 
1 libobjc.A.dylib     0x00007fff83258906 objc_object::sidetable_clearDeallocating() + 64 
2 libobjc.A.dylib     0x00007fff8323e651 objc_destructInstance + 145 
3 libobjc.A.dylib     0x00007fff8323e595 object_dispose + 22 
4 com.apple.CoreFoundation  0x00007fff84eea448 -[__NSArrayM dealloc] + 376 
5 libobjc.A.dylib     0x00007fff8325889c objc_object::sidetable_release(bool) + 236 
6 com.apple.Foundation   0x00007fff85747909 -[_NSXPCInterfaceMethodInfo dealloc] + 63 
7 libobjc.A.dylib     0x00007fff8325889c objc_object::sidetable_release(bool) + 236 
8 com.apple.CoreFoundation  0x00007fff84ed5db0 CFRelease + 304 
9 com.apple.CoreFoundation  0x00007fff84ee5b92 __CFBasicHashDrain + 498 
10 com.apple.CoreFoundation  0x00007fff84ed5e8e CFRelease + 526 
11 com.apple.Foundation   0x00007fff8578dd7a -[NSXPCInterface dealloc] + 28 
12 libobjc.A.dylib     0x00007fff8325889c objc_object::sidetable_release(bool) + 236 
13 com.apple.Foundation   0x00007fff8578df0c -[NSXPCConnection dealloc] + 281 
14 libobjc.A.dylib     0x00007fff8325889c objc_object::sidetable_release(bool) + 236 
15 libsystem_blocks.dylib   0x00007fff8d3166e5 _Block_release + 196 
16 libdispatch.dylib    0x00007fff90effe73 _dispatch_client_callout + 8 
17 libdispatch.dylib    0x00007fff90f035cd _dispatch_queue_drain + 1100 
18 libdispatch.dylib    0x00007fff90f03030 _dispatch_queue_invoke + 202 
19 libdispatch.dylib    0x00007fff90f02bef _dispatch_root_queue_drain + 463 
20 libdispatch.dylib    0x00007fff90f02a1c _dispatch_worker_thread3 + 91 
21 libsystem_pthread.dylib   0x00007fff88785a9d _pthread_wqthread + 729 
22 libsystem_pthread.dylib   0x00007fff887833dd start_wqthread + 13 

Thread 6 Crashed:: Qt bearer thread 
0 org.qt-project.QtNetwork  0x0000000100a541cb QNetworkConfigurationManagerPrivate::~QNetworkConfigurationManagerPrivate() + 107 
1 org.qt-project.QtNetwork  0x0000000100a5431e QNetworkConfigurationManagerPrivate::~QNetworkConfigurationManagerPrivate() + 14 
2 org.qt-project.QtCore   0x0000000100d72427 QObject::event(QEvent*) + 823 
3 org.qt-project.QtCore   0x0000000100d49588 QCoreApplication::notify(QObject*, QEvent*) + 104 
4 org.qt-project.QtCore   0x0000000100d4a212 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) + 1058 
5 org.qt-project.QtCore   0x0000000100d997db QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 59 
6 org.qt-project.QtCore   0x0000000100d46c1c QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 412 
7 org.qt-project.QtCore   0x0000000100b9c07e QThread::exec() + 110 
8 org.qt-project.QtCore   0x0000000100b9fc02 QThreadPrivate::start(void*) + 338 
9 libsystem_pthread.dylib   0x00007fff8878605a _pthread_body + 131 
10 libsystem_pthread.dylib   0x00007fff88785fd7 _pthread_start + 176 
11 libsystem_pthread.dylib   0x00007fff887833ed thread_start + 13 

Come puoi vedere, il thread 0 è terminato - siamo fuori dal main. Sono sicuro che c'è un codice di pulizia che non riesco a chiamare quando smaltiamo le nostre risorse, ma non so cosa possa essere.

Senza mettere tutta la nostra fonte qui, la catena di base delle chiamate sono state facendo è:

class RestServer : public QObject { 
RestServer::RestServer() { 
    _tcpServer = new QTcpServer(this); 
} 

void RestServer::listen(quint16 port) 
{ 
    if (!_tcpServer->listen(QHostAddress::LocalHost, port)) { 
     LOG_ERROR("RestServer", "Failed to start server at: " << port); 
     throw std::exception(); 
    } 
    _portNum = _tcpServer->serverPort(); 
    LOG_INFO("RestServer", "Server is listening at: " << _portNum); 
    connect(_tcpServer, SIGNAL(newConnection()), this, SLOT(connectSocket())); 
} 

Poi, nel nostro codice di test, abbiamo praticamente fare:

void RestAPIServer_test::responseCallback(QNetworkReply *reply) 
{ 
    auto response = reply->readAll(); 
    _uri = response; 

    reply->close(); 

    QCoreApplication::exit(); 
} 

TEST_F(RestAPIServer_test, urlWithPercents) 
{ 
    RestServer restServer(); 
    restServer.listen(0); 
    quint16 port = restServer.serverPort(); 

    // "widget/foo bar.txt" 
    QUrl serviceUrl(QString("http://localhost:%1/path/?path=widget%2Ffoo%20bar.txt").arg(port)); 

    QNetworkAccessManager networkManager(this); 
    connect(&networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(responseCallback(QNetworkReply*))); 

    QNetworkRequest request(serviceUrl); 
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); 
    networkManager.get(request); 

    QCoreApplication::exec(); 

    ASSERT_EQ(QString("path=widget/foo bar.txt"), _uri); 
} 

risposta

0

Il problema sembrava essere a causa di alcuni fili di rete legate creati da Qt ancora in corsa per un po 'dopo la chiamata a QCoreApplication :: quit() è stato chiamato, probabilmente perché è stato chiamato il comando quit() dalla funzione di callback registrata con QTcpSocket. La soluzione era di mettere un sonno di 1 secondo dopo la chiamata per uscire:

void RestAPIServer_test::responseCallback(QNetworkReply *reply) 
{ 
    auto response = reply->readAll(); 
    _uri = response; 

    reply->close(); 

    QCoreApplication::exit(); 

    // This prevents a shutdown race condition where Qt service 
    // threads continue to run after the call to exit(). 
    std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 
} 
0

Non è sicuro istanziare uno QObject in pila con un genitore. Guarda la riga

L'oggetto sarebbe stato distrutto due volte, il che non è possibile, quindi si vede l'incidente. Cambiamento che riga come segue (naturalmente, l'uso di variabili networkManager deve essere aggiornato):

QNetworkAccessManager* networkManager=new QNetworkAccessManager(this); 
+0

Grazie per il suggerimento. In realtà, una versione precedente di questo esempio stava facendo proprio quello che hai detto, ma l'ho modificato in una variabile stack in questo caso per vedere se il problema era dovuto a networkManager che va oltre lo scopo di questo codice. In entrambi i casi, si verifica il segfault occasionale. –

+0

Come si chiama 'quit()' su 'QCoreApplication' per interrompere il ciclo' exec() '? Ti suggerirei di inserire uno slot proxy tra il segnale e 'quit()' in cui potresti provare a distruggere il tuo server e il gestore degli accessi di rete in modo esplicito. Quindi si potrebbe promuovere il segnale allo slot 'quit()' direttamente o usando 'QTimer :: singleShot()' per assicurarsi che tutti i thread di rete siano finiti correttamente. Guarda quale risultato otterrai. –

+0

"Non è sicuro creare un'istanza di QObject sullo stack con un genitore." - questo è vero solo se il genitore può essere cancellato prima dell'oggetto nello stack, altrimenti l'oggetto viene rimosso dalla lista dei figli del genitore quando viene distrutto, quindi nessuna cancellazione doppia –

Problemi correlati