2016-03-17 13 views
5

単純なHTTPサーバーインターフェイスを提供するQt 5.5を使用するOS X C++アプリケーションがあります。これは、Qtの(http://doc.qt.io/qt-5/qtnetwork-fortuneserver-example.html)が提供するフォーチュンサーバの例と本質的に似ていますが、私たちが見ていると、時折、アプリケーションは次のスタックトレース(スレッド6クラッシュ)で、シャットダウン時にフォルトSEGされていることである。Qtネットワーククラスでシャットダウンの競合状態を回避する方法

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 

ご覧のとおり、スレッド0が完了しています。メインにはありません。私たちのリソースを処分しているときに呼び出すことができないいくつかのクリーンアップコードがあると確信していますが、それが何であるか分かりません。

ここまで私たちのすべてのソースをかけることなく、通話の基本的なチェーンがやったです:

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())); 
} 

そして、我々のテストコードでは、我々は基本的に行います。

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); 
} 

答えて

0

問題原因のQtで作成されたいくつかのネットワーク関連のスレッドがまだ呼び出し後のビットのために実行するように見えましたquit()がQTcpSocketで登録されたコールバック関数内から呼び出されたためと思われるため、QCoreApplication :: quit()が呼び出されました。解決策は、コール終了後に1秒間スリープ状態にすることでした。

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

それはに安全ではありません親とのスタックにQObjectをインスタンス化します。行を見てください

QNetworkAccessManager networkManager(this); 

オブジェクトは2回破壊されますが、これは可能ではないためクラッシュします。以下のように(もちろん、変数networkManagerの使用も更新する必要があります)、その行を変更します。

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

チップをありがとう。実際には、この例の以前のバージョンでは、あなたが言っただけで何やってましたが、私はこの問題は、このコードの範囲を超えての生活にNetworkManagerによるものであったかどうかを確認するために、この場合には、スタック変数にそれを変更しました。どちらの場合も、時折segfaultが発生します。 –

+0

'QCoreApplication'で' exec() 'ループを止めるために' quit() 'をどのように呼びますか?私はあなたが明示的にサーバーやネットワークアクセスマネージャを破壊しようとすることができている ')あなたは、信号と'(終了の間にプロキシスロットを挿入することを示唆しています。そして、あなたは '終了()'直接または 'QTimer :: SINGLESHOT()を使用して、スロット'すべてのネットワークスレッドが正しく終了されていることを確認するために信号を促進することができました。あなたが得られる結果を見てください。 –

+0

は、「親とのスタック上にQObjectをインスタンス化するのは安全ではありません。」 - それが唯一の真の親はおそらく破壊されたときにそれ以外の場合は、オブジェクトが子供の親のリストから削除されたスタック上のオブジェクトの前に削除することができるならば、これ。二重削除しない無 –

関連する問題