簡體   English   中英

什么是在linux上c ++ / Qt中解雇和忘記線程的最簡單方法?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM