雖然編寫了一個看似簡單的Qt應用程序部分,它將運行一個子進程並從其標準輸出中讀取數據,但我偶然發現了一個讓我感到困惑的問題。該應用程序應改爲從子數據塊(原始視頻幀)並對其進行處理,他們到達:QProcess因無明顯原因而死亡
- 開始QProcess中
- 收集數據,直到有一幀
- 過程框架是不夠
- 回到步驟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();
}
現在就莫名其妙的一部分。這個程序處理一個隨機數幀的就好了(我見過從十五個有什麼千餘),但最終停止,並抱怨說,QProcess中墜毀:
$ ./app
frame 1
...
frame 245
frame 246
frame 247
process state 0
process error 1
QIODevice error "Process crashed"
處理狀態0表示「未運行」和過程錯誤1意味着「墜毀」。我調查了一下,發現子進程收到一個SIGPIPE - 即父進程關閉了管道。但我有絕對沒有想法在哪裏和爲什麼會發生這種情況。還有其他人嗎?
整潔的建議,但不幸的是我沒有從strace那裏得到很多有用的信息。然而,它確實證實管道確實被關閉。我開始相信我可能沒有做錯任何事情,並且問題是由於Qt的一些內部競爭條件造成的。 – 2013-04-08 22:52:59
這是一個危險的結論 - 作爲一個試圖用Posix系統調用重寫QProcess只是爲了好玩的人,我確實承認它可能是非常誘人的:)。當然,你可以在''strace''的輸出中看到''close()''。如果這還不足以弄清楚爲什麼會發生這種情況,那麼您總是可以在像''gdb''這樣的調試器下運行整個事件,並在''close''中設置一個斷點/ catchpoint。 – 2013-04-09 14:38:18
我在Qt的代碼中找到了一些東西,我確實知道close()被調用的地方。現在......哈哈哈!我正要將一個鏈接粘貼到一個關於Qt-interest的電子郵件線索上,這個線索可能與這個問題有關,並且剛剛認識到它是你開始線程的。 :-)好吧,無論如何,[這裏](http://lists.qt.nokia.com/public/qt-interest/2009-May/006341.html)都是鏈接。我對發生的事情的印象是,主事件循環以某種方式得到關於在管道上等待的新數據的虛假通知,只是發現沒有真正存在的東西。 – 2013-04-10 15:38:27