2

EncodeThreadというカスタムQObjectクラスを作成しました。これは次のようになります。

class EncodeThread : public QObject {
    Q_OBJECT

public:
    void set(SWSL::Video* v, QStringList f, QDir vDir);
    void run();

public slots:
    void encode();

signals:
    void encodeProgress(int i);

private:
    SWSL::Video* video;
    QStringList files;
    QDir videoDir;
};

明らかなように、このクラスは外部ライブラリを使用してビデオをエンコードするために使用されます。Encode()には実際のエンコーディングルーチンが含まれています。run()はトラブルシューティング中に追加した関数ですが、明らかに機能していません。

void EncodeThread::run() {
    if (currentThread() != this) {
        // caller is in different thread.
        QMetaObject::invokeMethod(this, "encode", Qt::QueuedConnection);
    }
    else {
        encode();
    }
}

問題は、EncodeThreadインスタンスでQThreadとmoveToThread()関数を使用する場合、つまり何も起こらないように見えることです。データは書き込まれず、インスタンスは、エンコードされたファイルをディスクに保存する必要があるシグナルを発行しません。

encThread.set(video, files, videoDir);
connect(&encThread, SIGNAL(encodeProgress(int)), cookVideoProgress, SLOT(setValue(int)));
    connect(&encThread, SIGNAL(finished()), this, SLOT(videoCookEnd()));
    connect(this, SIGNAL(videoEncode()), &encThread, SLOT(encode()));
encThread.moveToThread(&thread);
    thread.start();

上記は、セットアップ全体が開始される方法です。EncThread変数とthread変数は、MainWindowクラスで宣言されています。シグナルを使用してメインスレッドからencode()を呼び出そうとした後、EncodeThreadのset()関数でencode()を呼び出しましたが、QMetaObjectが失敗しました。

私はスレッド化に不慣れではなく、ネイティブのWindowsスレッドとLinuxスレッド、およびさまざまなクロスプラットフォーム実装のスレッドを使用しましたが、QThreadsは本当に私を困惑させているようです。どんな提案も大歓迎です:)

4

3 に答える 3

1

EncoderThreadおそらくあなたの助けになるために遅れる方法ですが、ここにクラスを機能させる小さなデモプログラムがあります。それはおそらくあなたのデザイン(あなたの質問には断片しかありませんでした)と完全には一致しませんが、それはそれ自身のスレッドでオブジェクトインスタンスを実行し、それらが通信できるように信号/スロットを介して異なるスレッドで2つのオブジェクトを配線することを示しています:

#include <stdio.h>
#include <QObject>
#include <QThread>
#include <QtCore/QCoreApplication>

// QSleeper is just a toy utility class that makes the
//  protected QThread::sleep() family of functions
//  publicly accessible.  It's only use is for demo
//  programs like this
class Sleeper : QThread
{
public:
    static void sleep(unsigned long secs) { QThread::sleep(secs); }
    static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
    static void usleep(unsigned long usecs) { QThread::usleep(usecs); }

};


// an Encoder class that maintains itself on is own thread
class EncodeThread : public QObject {
    Q_OBJECT

public:
    EncodeThread();

public slots:
    void encode();

signals:
    void encodeProgress(int i);
    void finished();

private:
    QThread myThread;
};

EncodeThread::EncodeThread() {
    moveToThread(&myThread);
    myThread.start();
}


void EncodeThread::encode()
{
    printf("EncodeThread::encode() on thread %u\n", (unsigned int) QThread::currentThreadId());

    for (int i = 0; i < 6; ++i) {
        // encode for 1 second or so
        printf("EncodeThread::encode() working on thread %u\n", (unsigned int) QThread::currentThreadId());
        Sleeper::sleep(1);
        emit encodeProgress(i);
    }

    emit finished();
    printf("EncodeThread::encode() - done\n");
}




// a controller to manage and monitor an EncoderThread instance
class VideoEncoderController : public QObject
{
    Q_OBJECT
public:
    void start();

public slots:
    void setValue(int);
    void encodingDone();

signals:
    void encodingBegin();
};

void VideoEncoderController::start()
{
    printf("VideoEncoderController::start() on thread %u\n", (unsigned int) QThread::currentThreadId());
    emit encodingBegin();
}

void VideoEncoderController::setValue(int x)
{
    printf("VideoEncoderController::setValue(int %d) on thread %u\n", x, (unsigned int) QThread::currentThreadId());
}

void VideoEncoderController::encodingDone()
{
    printf("VideoEncoderController::encodingDone() on thread %u\n", (unsigned int) QThread::currentThreadId());
}




// a demo program that wires up a VideoEncoderController object to
//  an EncoderThread
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    EncodeThread encThread;
    VideoEncoderController controller;

    QObject::connect(&encThread, SIGNAL(encodeProgress(int)), &controller, SLOT(setValue(int)));
    QObject::connect(&encThread, SIGNAL(finished()), &controller, SLOT(encodingDone()));
    QObject::connect(&controller, SIGNAL(encodingBegin()), &encThread, SLOT(encode()));

    printf("hello world on thread %u\n", (unsigned int) QThread::currentThreadId ());

    controller.start();

    return a.exec();
}



#include "main.moc"
于 2011-05-06T07:17:49.737 に答える
0

QThreadではなく、を導出する必要がありますQObject。run()メソッドは。の抽象メソッドですQThread

于 2011-04-24T02:58:44.730 に答える
0

将来のプログラマーのために、私はこの答えを追加しています。Qtのマルチスレッドには一般的に3つのアプローチがあります。低レベル再利用(中レベルとしましょう)および高レベル

低レベルには、2つの異なるアプローチも含まれます。低レベルでは、QThreadクラスを継承し、内部で並行して実行するコードを提供できますvoid QThread::run() override;QThread::start()ドライブクラスを呼び出した後、コードインrunが実行されます。

Qtの低レベルマルチスレッドのもう1つのアプローチは、Qtのイベントループでのリレーです。このようにして、から駆動されるクラスを作成しますがQObject、必ずしもからではなく、このクラスをこのQThreadで新しいクラスに移動します。その後、そのオブジェクトを呼び出します(このQThreadオブジェクトはタイプのオブジェクトです。ここでサブクラス化する必要はありません。1つのオブジェクトをインスタンス化するだけです。コードで誤解されていると思います)。QThreadstart()QThreadQThreadQThread

オブジェクトを呼び出しstart()た後QThread、そのイベントループは別のスレッドで開始され、ドライブされたクラスのスロットに接続されているコード内の任意の場所からのシグナルは、これに対する最後の引数としてQObject使用しない限り、そのイベントループで並行して実行されます。Qt::DirectConnection

これらの2つのアプローチには、それぞれ長所と短所があります。サブクラス化QThreadして使用するときQthread::run()に、内部のコードがループ内runで実行されている場合while(true)、プロセッサのスレッドの1つは常にQthread::run()コードで占有され、プログラム内の他のスレッドのスレッドプールには含まれません。

このQObject::moveToThread()アプローチは、ほとんどの場合に役立ちます。ただし、QObjectドリブンクラスのスロットが1秒間に100回または1000回のように頻繁に呼び出される場合、スロットに渡される引数の可能性のためにメモリ使用量が増加し、この信号の一部がスロットに到達しない可能性があります。

于 2020-07-05T08:32:30.657 に答える