2013-04-06 5 views
2

서브 프로세스를 실행하고 표준 출력에서 ​​데이터를 읽는 Qt 애플리케이션의 겉으로보기에는 간단한 부분을 코딩하는 동안, 나는 정말 당황 스럽다. 애플리케이션은 구성 프로세스에서 데이터 블록 (원시 비디오 프레임)을 읽고이 도착하여 처리해야명백한 이유없이 QProcess가 죽는다

    한 프레임
  1. 프로세스 프레임 충분히 존재할 때까지
  2. 데이터가 모이는 QProcess 시작
  3. 2

단계로

  • 반환 생각은 신호와 슬롯을 사용하여 처리 루프를 구현하는 것이 었습니다 - 이것은 내가 아래에 제공하는 단순 제거 다운 예에서는 바보 보일 수 있지만, entirel을 보였다 원래 응용 프로그램의 프레임 워크 내에서 합리적입니다. 그래서 여기에 우리가 간다 :

    app::app() { 
        process.start("cat /dev/zero"); 
        buffer = new char[frameLength]; 
        connect(this, SIGNAL(wantNewFrame()), SLOT(readFrame()), Qt::QueuedConnection); 
        connect(this, SIGNAL(frameReady()), SLOT(frameHandler()), Qt::QueuedConnection); 
        emit wantNewFrame(); 
    } 
    

    내가 여기 사소한 과정 (cat /dev/zero) 우리는 데이터가 부족하지 않을 것을 확신 할 수 있도록를 시작합니다. 또한 두 개의 연결을 만듭니다. 하나는 프레임이 필요할 때 읽기를 시작하고 다른 하나는 프레임이 도착하면 데이터 처리 함수를 호출합니다. 이 간단한 예제는 단일 스레드에서 실행되므로 무한 재귀를 피하기 위해 대기열 유형으로 연결됩니다. wantNewFrame() 신호는 첫 번째 프레임의 수집을 시작합니다. 컨트롤이 이벤트 루프로 반환 될 때 처리됩니다.

    bool app::readFrame() { 
        qint64 bytesNeeded = frameLength; 
        qint64 bytesRead = 0; 
        char* ptr = buffer; 
        while (bytesNeeded > 0) { 
        process.waitForReadyRead(); 
        bytesRead = process.read(ptr, bytesNeeded); 
        if (bytesRead == -1) { 
         qDebug() << "process state" << process.state(); 
         qDebug() << "process error" << process.error(); 
         qDebug() << "QIODevice error" << process.errorString(); 
         QCoreApplication::quit(); 
         break; 
        } 
        ptr += bytesRead; 
        bytesNeeded -= bytesRead; 
        } 
        if (bytesNeeded == 0) { 
        emit frameReady(); 
        return true; 
        } else 
        return false; 
    } 
    

    프레임 읽기 : 기본적으로 데이터가 도착하면 버퍼에 채워집니다. 끝에있는 frameReady() 신호는 프레임이 준비되었음을 알리고 데이터 처리 기능을 실행합니다.

    void app::frameHandler() { 
        static qint64 frameno = 0; 
        qDebug() << "frame" << frameno++; 
        emit wantNewFrame(); 
    } 
    

    간단한 데이터 프로세서 : 프레임 수만 계산합니다. 완료되면 wantNewFrame()을 발급하여 새 읽기주기를 시작합니다.

    이것은 그 것이다. 완성을 위해 헤더 파일과 main()을 여기에 게시 할 것입니다.

    APP_H, :

    #include <QDebug> 
    #include <QCoreApplication> 
    #include <QProcess> 
    
    class app : public QObject 
    { 
    Q_OBJECT 
    public: 
        app(); 
        ~app() { delete[] buffer; } 
    
    signals: 
        void wantNewFrame(); 
        void frameReady(); 
    
    public slots: 
        bool readFrame(); 
        void frameHandler(); 
    
    private: 
        static const quint64 frameLength = 614400; 
        QProcess process; 
        char* buffer; 
    }; 
    

    MAIN.CPP : 기괴한 부분에 대한

    #include "app.h" 
    
    int main(int argc, char** argv) 
    { 
        QCoreApplication coreapp(argc, argv); 
        app foo; 
        return coreapp.exec(); 
    } 
    

    그리고 지금. 이 프로그램은 잘 프레임의 임의의 숫자를 (I 이상 만에 다섯 아무것도 본 적이) 처리하지만 결국 중단하고 QProcess 추락했다고 불평 : 프로세스 상태 0을 의미

    $ ./app 
    frame 1 
    ... 
    frame 245 
    frame 246 
    frame 247 
    process state 0 
    process error 1 
    QIODevice error "Process crashed" 
    

    은 "실행되지"와 프로세스 오류 1은 "충돌"을 의미합니다. 나는 그것에 대해 조사한 결과, 자식 프로세스가 SIGPIPE를 받았다는 것을 알았습니다. 즉, 부모가 파이프를 닫았습니다. 그러나 나는 을 전혀 가지고 있지 않다. 아이디어는 어디서 그리고 왜 일어나는가? 다른 사람 있습니까?

  • 답변

    0

    코드가 이상하게 보입니다 (readyRead 신호를 사용하지 않고 대신 지연된 신호/슬롯에 의존). 토론에서 지적한 것처럼 이미 비슷한 문제에 대해 물어 본 thread on the qt-interest ML을 보았습니다. 나는 그 때 QueuedConnection을 사용함을 깨달았습니다.왜 그것이 잘못되었는지 설명 할 수 없습니다. 큐에 든 신호는 "작동해야합니다"라고 생각합니다. 블라인드 샷은 Qt의 구현에서 사용되는 invokeMethod이 신호 전달 방식과 경쟁하기 때문에 Qt가 데이터를 처리하기 전에 읽기 버퍼를 비울 수 있습니다. 이는 Qt가 궁극적으로 0 바이트를 읽고 (올바르게) EOF으로 해석하여 파이프를 닫음을 의미합니다.

    참조 된 "Qt 작업 217111"을 더 이상 찾을 수 없지만 사용자가 예상대로 작동하지 않는 약 waitForReadyRead에 대한 Jira의 보고서가 두 가지 있습니다 (예 : QTBUG-9529.

    Qt의 "관심"메일 링리스트에이 방법을 사용하면 waitFor... 패밀리로부터 벗어날 수 있습니다. 나는 그들의 문서를 업데이트 할 것에 동의한다.

    +0

    깔끔한 제안이지만, 불행히도 strace에서 많은 도움이되는 정보를 얻지 못했습니다. 그러나 파이프가 실제로 닫혀 있음을 확인했습니다. 나는 잘못된 일을하지 않을 것이며 Qt의 내부 경쟁 조건으로 인해 문제가 발생한다고 생각하기 시작했습니다. –

    +0

    그건 위험한 결론입니다. PosPro syscalls로 QProcess를 재미로 재 작성하려고 시도한 사람으로서, 나는 그것을 유혹 할 수 있음을 인정합니다 :). 확실하게''strace''의 출력에서''close()''를 볼 수 있습니다. 이것이 왜 발생하는지 알기에 충분하지 않다면,''gdb''와 같은 디버거에서 모든 것을 실행하고 "close"에 중단 점/catchpoint를 설정할 수 있습니다. –

    +0

    나는 Qt의 코드를 다소 파고 있었고 close()가 호출 된 곳을 찾았습니다. 이제 ... 하하하! 나는이 문제와 관련이있을 수있는 Qt 관심사에 대한 전자 메일 스레드에 대한 링크를 붙여 넣으 려하고 있었으며 이제는 스레드를 시작한 사람이 누구인지 알게되었습니다. :-) 음, [여기] (http://lists.qt.nokia.com/public/qt-interest/2009-May/006341.html)는 어쨌든 링크입니다. 무슨 일이 일어나고 있는지에 대한 내 인상은 메인 이벤트 루프가 파이프에 대기중인 새 데이터에 대해 어떻게 든 잘못된 알림을 받으면서 실제로는 아무 것도 없다는 것을 알게됩니다. –

    관련 문제