2016-03-17 2 views
5

У нас есть приложение OS X C++ с использованием Qt 5.5, который обеспечивает простой интерфейс HTTP-сервера. Это по существу аналогично примеру Fortune Server, предоставляемой Qt (http://doc.qt.io/qt-5/qtnetwork-fortuneserver-example.html), но то, что мы видим, что иногда применение SEG разломообразования после завершения работы со следующей трассировки стека (поток 6 Грохот):Как предотвратить условия горения при работе с сетевыми классами 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 до сих пор работает на немного после вызова к QCoreApplication :: quit() был вызван, вероятно, потому, что quit() был вызван из функции обратного вызова, зарегистрированной в QTcpSocket. Решением было положить 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); 

Объект будет уничтожен дважды, что невозможно, так что вы увидите сбой. Изменить эту строку следующим образом (конечно, использование переменной networkManager также должно быть обновлено):

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

Спасибо за отзыв. На самом деле, предыдущая версия этого примера делала именно то, что вы сказали, но в этом случае я заменил его на переменную стека, чтобы убедиться, что проблема связана с тем, что networkManager не выходит за рамки этого кода. В любом случае происходит случайный segfault. –

+0

Как вы вызываете 'quit()' в 'QCoreApplication', чтобы остановить цикл' exec()? Я бы посоветовал вам вставить прокси-слот между вашим сигналом и 'quit()', в котором вы могли бы попытаться уничтожить свой сервер и диспетчер сетевого доступа явно. Затем вы можете продвигать сигнал на 'quit()' slot либо напрямую, либо с помощью 'QTimer :: singleShot()', чтобы гарантировать, что все сетевые потоки закончены правильно. Посмотрите, какой результат вы получите. –

+0

«Невозможно создать экземпляр объекта QObject в стеке с родителем». Это верно только в том случае, если родительский объект может быть удален до объекта в стеке. В противном случае объект будет удален из списка родительских списков детей при его уничтожении. нет double-deletion. –

Смежные вопросы