C++ 在c+;中启动并忘记线程的最简单方法是什么+;/linux上的Qt?
我正在编写一个应用程序,它嵌入了使用Qt同时运行的多个libVlc实例。vlc库中似乎存在一个bug,如果从Qt的GUI线程调用,有时libvlc_media_player_会停止死锁。在一个videolan论坛上,公认的解决方案是从另一个线程调用stop函数。我正在寻找一种参与最少且不太丑陋的方法,以便从不同的线程调用stop。我研究了使用QThreadPool,这正是针对这种情况的,但在我的特殊情况下,它并不能使解决方案变得漂亮 这是我的一段代码: VlcWidget.hC++ 在c+;中启动并忘记线程的最简单方法是什么+;/linux上的Qt?,c++,linux,multithreading,qt,C++,Linux,Multithreading,Qt,我正在编写一个应用程序,它嵌入了使用Qt同时运行的多个libVlc实例。vlc库中似乎存在一个bug,如果从Qt的GUI线程调用,有时libvlc_media_player_会停止死锁。在一个videolan论坛上,公认的解决方案是从另一个线程调用stop函数。我正在寻找一种参与最少且不太丑陋的方法,以便从不同的线程调用stop。我研究了使用QThreadPool,这正是针对这种情况的,但在我的特殊情况下,它并不能使解决方案变得漂亮 这是我的一段代码: VlcWidget.h class
class VlcWidget : public QWidget
{
Q_OBJECT
private:
// State
bool _isPlaying;
// The streaming source, title and quality data
VideoData _videoData;
VIDEO_QUALITY _quality;
// LibVlc related members
libvlc_instance_t *_vlcInstance;
libvlc_media_player_t *_vlcMediaPlayer;
libvlc_media_t *_vlcMedia;
int _vlcTrackID;
}
VlcWidget.c
void VlcWidget::Play()
{
if(_videoData.Source() != "" && !_isPlaying)
{
// Create a new media descriptor
_vlcMedia = libvlc_media_new_location(
_vlcInstance,
_videoData.Source().toStdString().c_str());
// Tell the user about incorrect URL
if(_vlcMedia == NULL)
{
QMessageBox::information(this,
_videoData.Title(),
"Unable to open source Url.\nPlease check the source and try again.");
return;
}
libvlc_media_player_set_media(_vlcMediaPlayer, _vlcMedia);
libvlc_media_release(_vlcMedia);
libvlc_media_player_set_xwindow(_vlcMediaPlayer, parentWidget()->winId());
libvlc_media_player_play(_vlcMediaPlayer);
_vlcTrackID = libvlc_audio_get_track(_vlcMediaPlayer);
_isPlaying = true;
}
}
void VlcWidget::Stop()
{
if(_isPlaying)
{
libvlc_media_player_stop(_vlcMediaPlayer);
_vlcTrackID = -1;
_isPlaying = false;
}
}
我使用QthreadPool的解决方案如下所示:
class AsyncVlcPlay : public QRunnable
{
private:
// State
bool *_isPlaying;
// LibVlc related members
libvlc_instance_t *_vlcInstance;
libvlc_media_player_t *_vlcMediaPlayer;
libvlc_media_t *_vlcMedia;
int *_vlcTrackID;
public:
virtual void run();
}
AsyncVlclay::run()的作用与VlcWidget::Play()的作用完全相同,只是添加了简单的锁定。对于VlcWidget::Stop(),我还需要一个类似的类。我不喜欢这个解决方案,因为我不应该真的需要两个新的类来实现我的目标。更糟糕的是,我必须将VlcWidgets私有成员传递给另一个类的对象。我很确定有一个非常简单的方法我不知道,希望你们中的一个能帮我。谢谢
(事实上,我并不需要VlcWidget::Play()在另一个线程上,但我希望保持播放和停止对称)我将使用QThread解决这个问题。它的名字实际上是误导性的,因为它实际上不是一个线程,而是一个线程控制器,非常容易使用 从QObject继承的任何类都可以移动到线程,线程之间的通信可以通过信号/插槽机制完成。因此,您可以这样做:-
class VlcObject : public QObject
{
Q_OBJECT
public slots:
void Run();
private slots;
void StopVlc();
};
此类可以包含所有Vlc对象/实例。然后创建一个线程控制器对象,并将VlcObject实例移动到新线程:-
QThread* pThread = new QThread(this); // where this is a parent, running on the main thread
VlcObject* pVlcObj = new VlcObject;
pVlcObj->moveToThread(pThread);
// Note, this is Qt 5 connect style - Qt 4 connections also work
connect(pThread, &QThread::started, pVlcOj, &VlcObject::Run();
// Start the thread running
pThread->start();
假设QVlcWidget是一个GUI类,带有一个名为pStopVlc的按钮,然后通过将该按钮连接到VlcObject的StopVlc函数来调用另一个线程的VlcObject上的stop:-
connect(pStopVlc, &QPushButton::released, pVlcObj, &VlcObject::StopVlc);
或者,您可以在线程退出时调用StopVlc,并且QThread可以在停止时自行清理:-
connect(pThread, &QThread::finished, pThread, &Qthread::deleteLater);
下面是我的(部分)代码,用于将SWI Prolog语法高亮显示耦合到Qt
// start highlighting, using SWI-Prolog syntax analyzer to collect structured data
//
void pqSource::startHighliter() {
auto f = [](QString file, pqSyntaxData* psd) {
SwiPrologEngine::in_thread _it;
try {
// ?? PlCall("consult", V(A(file)));
qDebug() << "running syntax color on" << file << "thread" << CT;
int rc = PlCall("syncol", PlTermv(A(file), PlTerm(psd)));
qDebug() << "syncol" << rc;
}
catch(PlException e) {
qDebug() << t2w(e);
}
};
// collect structure asyncronously
auto w = new QFutureWatcher<void>;
connect(w, SIGNAL(finished()), this, SLOT(runHighliter()));
// since could be a slow task, place a visual hint to what's going on...
CenterWidgets((sd = new pqSyntaxData)->pgb = new QProgressBar(this));
QTextCursor c = textCursor();
c.movePosition(c.End);
sd->pgb->setMaximum(c.position());
connect(sd, SIGNAL(onProgress(int)), sd->pgb, SLOT(setValue(int)));
sd->pgb->show();
// run the Prolog snippet in background (hl pointer)
w->setFuture(QtConcurrent::run(f, file, sd));
}
//开始突出显示,使用SWI Prolog语法分析器收集结构化数据
//
void pqSource::starthighlittle(){
自动f=[](QString文件,pqSyntaxData*psd){
swiprogene::in_thread\u it;
试一试{
//?PlCall(“咨询”,V(文件));
qDebug()也许这就是你想要的。@thuga-非常感谢!这正是我想要的:)如果你要使用QtConcurrent,我建议你先读一读:只要QtConcurrent的基本功能仍然存在,他们说会存在,我的应用程序就应该很好。我喜欢你在堆上创建线程的部分,并且把它忘得一干二净在连接到deleteLater插槽之后!我不知道你能做到这一点(我在Qt中只有一周大)。那么->moveToThread是否意味着pVlcObj将来所做的一切都将在新线程上?这可能不是我想要的。@Kulki您可以向pVlcObj添加信号并连接它们,使其触发另一个线程上的插槽thread@ratchetfreak-我不确定如何强制从另一个线程调用插槽?@Kulki在示例中st向VlcObject添加一个信号,然后在移动到线程后执行连接(pVlcObj,&VlcObject::my_signal,this,&VlcWidget::listingslot)
。Qt将自动使用排队连接