2017-03-01 6 views
0

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; 

} 
+0

最初に、モデルにミューテックスで保護されたデータを保存することをお勧めします。ビューはモデルの 'data()'メソッドをかなり頻繁に呼び出すので、並行性が不十分であっても、mutexのロックとアンロックのオーバーヘッドで十分です。 – Dmitry

+0

データが十分に重い場合は、データの軽量「ビュー」を格納する実際のモデルにデータ変更を通信するいくつかの 'QObject'でその管理をカプセル化することができます。たとえば、データに長いテキストモデルには、ビューに表示するために、各アイテムの最初の140文字を含めることができます。フルデータへのアクセス(モデルに接続されたビューではアクセスが頻繁に行われないようにするためではありません)では、データを同期的に取得する独自のモデルAPIを作成することができます。 – Dmitry

+0

それは確かに正しい方法です。しかし、私が使用しているフレームワークによって、アップデートを処理するためのboost :: asio :: serviceの使用は強制されます。 一方、QAbstractItemModelインターフェイス関数がスローしないと、元のコードでも機能する可能性があります。 GUIスレッドがdata()コール中にprocessUpdate()がlayoutChanged()を発行し、mutexをロックするのを待っている場合、何も悪いことは起こりません。 data()は何らかの間違ったデータ(または空のQVariant()かもしれない)を返し、数分間それを表示し、シグナルを処理し、すぐに正しいデータの表示を開始します。 – thedimitrius

答えて

0
自分の質問への答えが見つかり

: モデルが異なるQThreadに属している場合は、このモデルの信号はQtの:: QueuedConnectionを使用して表示するために接続され、それは大丈夫です。 ModelがGUI QThread(QCoreApplication :: instance() - > thread())に属している場合、Modelのスロットはすぐに実行され、data()、columnCount()したがって、それは大丈夫ではありません。

関連する問題