5

非 GUI スレッドで実行している QWidget::update() でアプリケーションがクラッシュすることがあります。

リモートホストからビデオフレームを受信して​​ QWidget に表示するアプリケーションを開発しています。

この目的のために、デコードされた画像を提供する libVLC ライブラリを使用します。別の libVLC スレッドで実行されている libVLC コールバックでイメージを受け取ります。このコールバックでは、QWidget::update() メソッドを実行しようとしています。アプリケーションがクラッシュする場合があり、コールスタックはこのメソッドのどこかにあります。これが私のコールバックコードです:

//! Called when a video frame is ready to be displayed, according to the vlc clock. 
//! \c picture is the return value from lockCB().

void VideoWidget::displayCB(void* picture)
{
    QImage* image = reinterpret_cast<QImage*>(picture);

    onScreenPixmapMutex_.lock();
    onScreenPixmap_ = QImage(*image);
    onScreenPixmap_.detach();
    onScreenPixmapMutex_.unlock();

    delete image;

    update();
}

Qt では、メイン スレッド外での GUI 操作が許可されていないことを知っています。しかし、ドキュメント QWidget::update() によると、Qt がメイン イベント ループに戻ったときに処理するためのペイント イベントをスケジュールするだけで、すぐに再ペイントは行われません。

問題は、「メイン スレッド外の GUI 操作は許可されない」という規則が QWidget::update() に適用されるかどうかです。この操作は「GUI操作」に属しますか?

私は Qt 4.7.3 を使用しています。クラッシュは Windows 7 と Linux で再現されます。

4

4 に答える 4

7

マンデルブロの例をご覧ください。その例では、ワーカー スレッドが画像を生成し、それをシグナル/スロット メカニズムでレンダリング ウィジェットに渡しています。同じ方法を使用してください!

例にあるように新しい updatePixmap() スロットを実装する代わりに、ウィジェットのupdate()スロットを直接接続することもできます。

あなたのコードから、同時アクセスを提供するミューテックスがあることがわかります。したがって、更新スロットを直接使用するのは簡単です。

Qt ではメイン スレッド外の GUI 操作が許可されていないため、どちらの方法でもシグナル/スロット メカニズムが使用されます。

于 2011-06-21T06:23:31.913 に答える
5

問題は、「メイン スレッド外の GUI 操作は許可されない」という規則が QWidget::update() に適用されるかどうかです。この操作は「GUI操作」に属しますか?

はい。更新は GUI 操作に属します。ドキュメントによると、すべての QWidget および派生クラスはメイン スレッドでのみ使用できます。これは一般的なことであり、特定の関数はスレッドセーフであると述べている場合がありますが、この場合 update() はそうではないため、他のスレッドから呼び出すのは安全ではありません。

シグナル/スロット メカニズムが機能するのは、Qt が (別段の指示がない限り) イベントを使用して、あるスレッドのスロットを別のスレッドのシグナルによってトリガーできるようにするためです。シグナル/スロットを使用し、Qt に特別なスレッド処理を行わないように指示すると、クラッシュが再発します。

于 2011-06-23T17:22:24.650 に答える