2012-06-07 6 views
0

시작시 주 스레드에서 두 개의 스레드를 시작하는 Qt 응용 프로그램이 있습니다. 이 두 스레드는 모두 QNetworkAccessManager 오브젝트의 고유 한 인스턴스를 사용하여 네트워크 요청을 작성합니다. 내 프로그램은 시간의 약 50 %를 계속 충돌하고 어떤 스레드가 충돌하는지 모르겠습니다.2 스레드에서 2 네트워크 요청을 만들 때 Qt 응용 프로그램이 작동을 멈 춥니 다.

두 스레드간에 직접 데이터 공유 또는 신호가 발생하지 않습니다. 특정 이벤트가 발생하면 스레드가 주 스레드에 신호를 보냅니다. 그러면 주 스레드가 두 번째 스레드에 신호를 보냅니다. 그러나 로그를 인쇄하면 신호가 발생하는 동안 충돌이 발생하지 않는다는 것이 확실합니다.

두 스레드의 구조는 다음과 같습니다. URL을 제외하고는 스레드의 차이는 거의 없습니다 등

MyThread() : QThread() { 
    moveToThread(this); 
} 

MyThread()::~MyThread() { 
    delete m_manager; 
    delete m_request; 
} 

MyThread::run() { 
    m_manager = new QNetworkAccessManager(); 
    m_request = new QNetworkRequest(QUrl("...")); 

    makeRequest(); 
    exec(); 
} 

MyThread::makeRequest() { 
    m_reply = m_manager->get(*m_request); 
    connect(m_reply, SIGNAL(finished()), this, SLOT(processReply())); 
    // my log line 
} 

MyThread::processReply() { 
    if (!m_reply->error()) { 
     QString data = QString(m_reply->readAll()); 
     emit signalToMainThread(data); 
    } 
    m_reply->deleteLater(); 
    exit(0); 
} 

이제 이상한 것은 내가 스레드 중 하나를 시작하지 않는 경우, 프로그램이 잘 실행, 또는 적어도에 충돌하지 않는있다 약 20 건의 호출. 두 스레드가 차례로 실행되면 프로그램이 중단되지 않습니다. 두 스레드를 동시에 시작하고 실행하는 경우 프로그램은 시간의 반에 대해서만과 충돌합니다.

로그에서 수집 한 또 다른 흥미로운 점은 프로그램이 중단 될 때마다 my log line이라는 줄이 두 스레드에서 마지막으로 실행된다는 것입니다. 그래서 어떤 쓰레드가 충돌을 일으키는 지 모르겠습니다. 그러나 QNetworkAccessManager가 어떻게 든 비난받을 것으로 의심됩니다.

나는 충돌을 일으키는 것에 대해 꽤 공백이다. 나는 어떤 제안이나 조언을 주셔서 감사합니다. 미리 감사드립니다.

답변

0

우선 you're doing it wrong! 처음 스레딩을 수정하십시오

// EDIT 이 패턴을 사용한 경험으로 많은 불분명 한 충돌이 발생할 수 있음을 알고 있습니다. 나는이 일을 정리하는 것으로부터 시작할 것인데, 그것은 어떤 일을 바로 잡을 수 있고 문제를 명확하게 찾을 수 있기 때문입니다. 또한 나는 어떻게 당신이 makeRequest을 호출하는지 모르겠다. QNetworkRequest에 대해서도. 데이터 구조이므로 힙을 만들 필요가 없습니다. 스택 구조만으로 충분할 것입니다. 또한 m_reply 포인터를 덮어 쓰지 않도록 (또는 여하튼) 보호해야합니다. makeRequest 번으로 전화하십니까? 그렇게하면 이전 요청이 완료된 후 현재 처리 된 요청을 삭제할 수 있습니다. 하여 makeRequest의

  1. 먼저 호출이 m_reply 포인터를 할당 : 두 번하여 makeRequest를 호출하는 경우 발생하는 일

    .

  2. makeRequest의 두 번째 호출은 m_reply 포인터를 두 번째로 할당합니다 (지정된 포인터를 바꾸지 만 포인터가있는 객체는 삭제하지 않음)
  3. 두 번째 요청이 먼저 완료되기 전에 processReply가 호출됩니다. deleteLater가 두 번째 대기열에 있습니다.
  4. eventloop에서 두 번째 응답이 삭제되었으므로 지금부터 m_reply 포인터가 임의의 (삭제 된) 메모리를 가리키고 있습니다.
  5. 첫 번째 응답이 완료되어 다른 processReply가 호출되지만 가비지를 가리키는 m_reply에서 작동하므로 m_reply에서 모든 호출이 중단됩니다.

가능한 시나리오 중 하나입니다. 그래서 당신은 매번 추락하지 않습니다.

회신을 마치면 exit (0)을 호출하는 이유는 확실하지 않습니다. makeRequest 호출을 한 번 이상 사용하면 여기에도 올바르지 않습니다. QThread는 스레드 풀이 아닌 단일 스레드에 대한 인터페이스임을 기억하십시오. 따라서 스레드 인스턴스가 실행 중일 때 start() 두 번째로 호출 할 수 없습니다. 진입 점 run()에서 네트워크 액세스 관리자를 만드는 경우 exec() 이후 같은 위치에서 삭제해야합니다. exec()이 차단되어 있으므로 스레드가 종료되기 전에 개체가 삭제되지 않습니다.

+0

나는 애플리케이션 개발에 상당히 늦은 2 개의 게시물 (잘못된 길과 올바른 길)을 발견했다. 내 자바 배경도 도움이되지 않았다. 스레딩을하기 위해 일반적으로 스레드를 확장한다. 이 문제는 스레딩이 아닌 네트워크 액세스 관리자 자체에서 발생하는 것으로 보입니다. 문제를 재현하는 베어 본 코드 스 니펫으로 주어진 접근 방식을 시도해 보겠습니다. 내가 누락 된 QNetworkAccessManager의 뉘앙스에 대한 의견을 보내주십시오. 감사. – Sameer

+0

내 편집 된 답변보기 –

+0

그리고 다른 편집 –