在线程内启动 QProcess

Posted

技术标签:

【中文标题】在线程内启动 QProcess【英文标题】:Starting QProcess inside a thread 【发布时间】:2015-04-18 13:54:03 【问题描述】:

我已经为这个基本问题苦苦挣扎了一段时间。 我正在尝试从一个线程开始一个QProcess。启动进程工作正常,进程正常运行,但我的问题是永远不会发出 finished() 信号。

这是我的例子:

我的类变量是

std::atomic<bool>  recording;
QProcess proc;
std::unique_ptr<std::thread> recordingThread;

班级:

Recorder::Recorder(ParentClass *parent): QObject(parent)

    connect(&proc,SIGNAL(finished(int)),this,SLOT(finishedFFMPEG())); 


void Recorder::start()

    if (!recordingThread)
        recording = true;
        recordingThread.reset(new std::thread(&Recorder::recordThread, this));
    


void Recorder::recordThread()

    while(recording)
        //writing frame
    
    proc.start("C:\\ffmpeg.exe", QStringList() <<"-i"<< picDir.c_str() << "-r"<< "30" << "-vcodec"<< "ffv1" << filename.c_str());
    proc.waitForStarted();      


void Recorder::stop()

    if (recordingThread) 
        recording = false;
        recordingThread->join(); recordingThread.reset();  
    


void Recorder::finishedFFMPEG()
    qDebug() << "finished";

start()stop() 是从我的 ParentClass 中的另一个非 GUI 线程调用的。

我尝试了一切,从使用指针、将recordThread() 作为QThread 运行并在stop() 函数中启动QProcess,但我根本没有收到来自进程的finished() 信号。该过程本身正在正确执行。我知道问题在于不同的事件循环。

如何实现在recordThread() 完成后启动进程并捕获QProcess finished() 信号的目标?

【问题讨论】:

你在这里使用 std::thread 而不是 QThread 有什么原因吗? 就像我在帖子中所说的,我确实尝试使用 QThread,但结果相同。 你考虑过使用QFuture&lt; T &gt; QtConcurrent吗?我尽可能多地使用它,它是高水平的,只是省去了很多麻烦+正确利用所有核心 这可能是个愚蠢的问题,但你的线程有事件循环吗? 【参考方案1】:

我不能说我很惊讶你的构造不起作用。您在不同的线程中使用 std::thread 执行成员函数 recordThread()。到现在为止还挺好。在 recordThread() 你有一个循环,看起来它收集/创建/写入帧。一旦离开循环,帧就会通过 QProcess 传递给 ffmpeg。至少这是你的意图。我做对了吗?

现在,在 stop() 中清除记录标志,这会导致 while 循环结束。 QProcess 启动。但与此同时,您结束了该 QProcess 所在的 recordThread() 线程。而且您希望不仅 QProcess 能够幸存下来,它可能会这样做,而且所有信号/插槽连接都保持完好?

我不完全知道 QProcess 会发生什么、可能的竞争、阻塞/非阻塞效应,但我敢打赌你的问题正是在这个领域。

还有一件事……我认为在线程 A 中创建 QProcess 并不健康,但像你一样在线程 B 中启动它。

我会尝试这样的事情(未经测试):

while(recording)
 //writing frame

QProcess p;
connect(&p,SIGNAL(finished(int)),this,SLOT(finishedFFMPEG()));
p.start(...your ffmpeg stuff...);
p.waitForFinished(-1);

在finishedFFMPEG()中

recordingThread->join(); recordingThread.reset();

然后线程被杀死,当 QProcess 完成时。

【讨论】:

我真的不想在 QProcess 完成之前阻止recordingThread() 事件,因为我希望在前一个线程的QProcess 仍在运行时启动一个新的recordingThread()。我可能会创建多个recordingThreads()并像你说的那样阻止事件循环来实现这一点,因为它似乎没有其他方法 您的方法并没有那么错误。只是不要将 QProcess 放入同一个函数中,该函数用于准备数据并在另一个线程中执行。将您的 recordingThread() 变成两个函数......一个带有 while 循环,一个带有 QProcess,你很好。 顺便说一句...我的解决方案对你来说已经足够好了。 QProcess(或者更好的是waitForFinished)是阻塞的,但只在这个特定的线程中。没有什么能阻止您创建更多的recordingThread() 线程。您的主线程中没有任何内容被阻塞。 嗯..我不明白你为 QProcess 创建自己的函数的意思。完成recordThread()中的任务后如何调用这个函数?我应该为它创建一个自己的线程吗? 正如我所说,您可以像我指出的那样保留代码。阻塞是 recordThread() 本地的,不会影响程序的其余部分。如果您不喜欢这样,请在 while 循环之后立即发出信号。您可以在主线程中捕获它并在那里启动 QProcess。同样,在插槽中收到此信号后终止线程。目前,您在 QProcess 完成并发送完成信号之前杀死线程。

以上是关于在线程内启动 QProcess的主要内容,如果未能解决你的问题,请参考以下文章

无法在 45 秒内启动意图。也许主线程在合理的时间内没有空闲?

在 C++ 中的线程内启动和停止循环

使用委托在另一个 Sub 内启动线程

为何只能在其关联的线程内启动timer?(Qt会检查一致性,否则就不执行)

JMter随记

线程实现连续启动停,并在某一时间段内运行