QAbstractItemModel
の実装では、いくつかのイベントをリッスンしており、別のスレッドで更新を処理しています。 更新を処理すると、モデルのレイアウトやデータが変更されることがあります。 データ自体の記憶はboost::mutex
- 保護され、QAbstractItemModel
のインタフェース関数(私が正しく理解していれば、GUIスレッドで実行されます)が実行され、更新処理関数(別スレッド)がmutexをロックします。 data()/ rowCount()/同じものを同時に取得しようとしているものと同じミューテックスをロックしている間、layoutChanged/dataChangedシグナルを出すことはできますか?QAbstractItemModelスレッドの安全性
コードの一部:
class MyItemModel : public QAbstractItemModel {
Q_OBJECT
public:
void processUpdate(const Update& update) {
Mservice.post([this, update]() {
boost::lock_guard<boost::mutex> lock (Mlock);
bool willModifyLayout = checkWillModifyLayout(update)
bool willModifyData = checkWillModifyData(update);
if (willModifyLayout) {
emit layoutAboutToBeChanged();
}
Mdata.processUpdate(update);
if (willModifyLayout) {
emit layoutChanged();
}
else if (willModifyData) {
emit dataChanged();
}
});
}
virtual QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE {
boost::lock_guard<boost::mutex> lock (Mlock);
if (index.isValid()) return Mdata.data(index, role);
}
private:
boost::mutex Mmutex;
boost::asio::service Mservice;
boost::asio::thread MserviceThread;
DataStorage Mdata;
}
最初に、モデルにミューテックスで保護されたデータを保存することをお勧めします。ビューはモデルの 'data()'メソッドをかなり頻繁に呼び出すので、並行性が不十分であっても、mutexのロックとアンロックのオーバーヘッドで十分です。 – Dmitry
データが十分に重い場合は、データの軽量「ビュー」を格納する実際のモデルにデータ変更を通信するいくつかの 'QObject'でその管理をカプセル化することができます。たとえば、データに長いテキストモデルには、ビューに表示するために、各アイテムの最初の140文字を含めることができます。フルデータへのアクセス(モデルに接続されたビューではアクセスが頻繁に行われないようにするためではありません)では、データを同期的に取得する独自のモデルAPIを作成することができます。 – Dmitry
それは確かに正しい方法です。しかし、私が使用しているフレームワークによって、アップデートを処理するためのboost :: asio :: serviceの使用は強制されます。 一方、QAbstractItemModelインターフェイス関数がスローしないと、元のコードでも機能する可能性があります。 GUIスレッドがdata()コール中にprocessUpdate()がlayoutChanged()を発行し、mutexをロックするのを待っている場合、何も悪いことは起こりません。 data()は何らかの間違ったデータ(または空のQVariant()かもしれない)を返し、数分間それを表示し、シグナルを処理し、すぐに正しいデータの表示を開始します。 – thedimitrius