[英]What's the C++ 11 way to fire off an asynchronous task and forget about it?
[英]What is the simplest way to fire and forget a thread in c++ / Qt on linux?
我正在編寫一個嵌入多個使用Qt同時運行的libVlc實例的應用程序。 vlc庫中似乎存在一個錯誤,如果從Qt的GUI線程調用,有時libvlc_media_player_stop會死鎖。 在其中一個videolan論壇上,接受的解決方案是從另一個線程調用stop函數。 我正在尋找最少參與且不太難看的方法來從不同的線程調用stop。 我看着使用QThreadPool,這意味着完全適用於這種情況,但在我的特殊情況下,它並沒有使解決方案很好。
這是我的一段代碼:
VlcWidget.h
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();
}
並且AsyncVlcPlay :: run()與VlcWidget :: Play()完全相同,並添加了簡單鎖定。 而且我還需要一個類似VlcWidget :: Stop()的類。 我不喜歡這個解決方案,因為我不應該為我想要實現的目標真正需要2個新類。 更糟糕的是,我必須將VlcWidgets私有成員傳遞給另一個類的對象。 我很確定這是一種非常簡單的方式,我不知道,並希望你們中的一個人可以幫助我。 謝謝!
(事實上,我真的不需要VlcWidget :: Play()在另一個線程上,但我想保持Play和Stop對稱)
我會用QThread來解決這個問題。 它的名字實際上是誤導性的,因為它實際上不是一個線程,而是一個線程控制器,非常容易使用。
從QObject繼承的任何類都可以移動到一個線程,並且可以使用signal / slot機制完成線程之間的通信。 因此,您可以這樣做: -
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是一個帶有名為pStopVlc的按鈕的GUI類,則可以通過將按鈕連接到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));
}
我想你可能對lambda的使用感興趣...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.