マニュアルメモリ管理は不要です。あなたはQtを活用してそれを行うべきです。シグナルスロット接続を介して画像を渡すことができ、その値が自動的にコピーされるという事実を利用することができ、そのアクセスはQtによって自動的に同期されます。
は、ここでコンパイラをさせる、非常に簡単に、あなたがそれを行うことができる方法ですあなたのためのリソース管理のすべてのハードワークを行います。
// https://github.com/KubaO/stackoverflown/tree/master/questions/imageloader-36265788
#include <QtWidgets>
#include <QtConcurrent>
まずは、映像ソースである信号を持つクラスを持ってみましょう。スレッドの境界を越える必要がある場合は、Qtによって自動的にコピーが行われるため、const参照型のイメージを提供するシグナルがあります。
class ImageSource : public QObject {
Q_OBJECT
public:
Q_SIGNAL void hasImage(const QImage & image);
メソッドがイメージを生成し、シグナルを放出します。 hasImage
シグナルで自動接続が使用されている限り、このメソッドは任意のスレッドで安全に実行できます。私たちの場合、私たちは常にワーカースレッドからこのメソッドを実行しますが、メインスレッドからもこのメソッドを実行できます。唯一の違いはパフォーマンスです。
/// This method is thread-safe (ignoring the UB of incrementing a shared int)
void generate() {
static auto counter = 0;
QImage img(128, 128, QImage::Format_ARGB32);
img.fill(Qt::white);
QPainter p(&img);
p.drawText(img.rect(), Qt::AlignCenter, QString::number(counter++));
p.end();
emit hasImage(img);
}
};
私たちは、そのクラスのインスタンスが必要になりますし、何かが上の画像を表示する - QLabel
、言う:
int main(int argc, char ** argv) {
QApplication app{argc, argv};
ImageSource source;
QLabel label;
label.show();
我々は今、ラベルの設定ファンクタにhasImage
を接続することができますサイズを設定し、画像を設定します。その後、グローバルプールから直ちにワーカースレッドでイメージジェネレータを再度実行します。それはQtConcurrent::run
によって自動的に処理されます。
ファンクタはメインスレッドで実行されます。これは、コンテキストパラメータをconnect
:connect(--, --, context, --)
に指定することで保証されます。ファンクタはlabel.thread()
で動作します。
QObject::connect(&source, &ImageSource::hasImage, &label, [&](const QImage & image){
label.setFixedSize(image.size());
label.setPixmap(QPixmap::fromImage(image));
QtConcurrent::run(&source, &ImageSource::generate);
});
接続は、受信対象のスロットコール(label
)スレッドのイベントキューの転記にhasImage
信号の結果を呼び出す効果自動であるので - ここで、メインスレッドのキュー。イベントループは、スロットコールをピックアップして実行します。したがって、ワーカースレッドでhasImage
を呼び出しても、イメージは自動的にコピーされ、メインスレッドのファンクタに渡されます。
最後に、最初のイメージを生成してプロセスを開始します。終わりに
QtConcurrent::run(&source, &ImageSource::generate); // generate the first image
return app.exec();
}
#include
は、信号hasImage
信号の実装、ImageSource
クラスを記述するメタデータを提供するために必要とされます。これはmocによって生成されます。
#include "main.moc"
これは完全なコードです。これを新しいプロジェクトに貼り付けてコンパイルして実行することができます。またはgithubのリンクから完全なプロジェクトをダウンロードしてください。
私のマシンで約1000/sの速度でピックスマップを更新するラベルを表示します。アプリケーションは完全に応答します。ウィンドウを自由に移動し、いつでも終了できます。
スレッドイメージローダーの別の例については、this answerを参照してください。
スタックに 'QImage'を割り当ててみませんか? – Drop
私は、将来的に起こりうるバグを回避するためにどのように機能するのだろうか。 – Nyaruko
この現象は説明されていません。我々は通常const参照が常に有効であると仮定します(存在しないかどうかを検証する方法はありません。基礎となるストレージの参照を解放することは、決して良い考えではありません。もちろん、 'QPainter'はスレッドセーフではありません。不明な点がある場合は、オープンソースライブラリの内部を理解する最善の方法は、ソースコードをダウンロードして読むことです。それはおそらくあなたの最善の策です。 – Drop