イベントキューでの操作の順序QT GUIの問題を解決するために

オリジナル:https://www.cnblogs.com/Philip-Tell-Truth/p/6295186.html

異常動作シーケンスによって引き起こされるGUIの問題

時々、私たちはGUIプログラムを書くために時間を使うことで、この問題が発生します:例えば、プロセスで、GUIの一覧を設立します。このリストは、継続的に時間をかけて更新され、操作はGUIの内容のリストを読み込みます。

プログラムがある場合は、プログラムをマルチスレッドが、唯一のGUIのスレッドに加えて動作しますが、他のスレッドがこのリストのGUIを操作されていない場合、問題は非常に簡単です、単にそれにmutexロックを追加します。GUIスレッド自体もこのリストを操作する場合でも、問題は非常に面倒です。

私たちは、簡単にGUIスレッドが(選択など)、そして残念ながら、この時、他のスレッドでは、これらのエントリを保つ方法へのポインタをスレッドリスト内のエントリのいくつかを読んでのようなシナリオを想像することができますそこリストにいくつかのエントリを削除する要求の必要性があり、これらのエントリのいくつかは、私たちの選択に含まれている、我々は、ほとんどすべての操作GUIの言語の動作GUIのスレッドを入力する際に​​知っておく必要があり、我々はちょうど選びましたエントリーの方法が中断され、その後、メソッドへのエントリを削除する時期を再度選択した入力方法に戻ったら、エントリを削除した後、私たちは、その後、削除されたエントリの一部を選択そう先に進む前に、当社の要件を満たしていません。

あなたは一般的に使用C#、独自の言語を持っていないJAVAのメモリ管理を使用している場合、それは大丈夫ですが、結果が間違っているかもしれないが、我々は自分自身のメモリ管理を書くために、このC ++を使用する必要がある場合、それはおそらく、我々は動作しますですメモリオブジェクトが解放され、プログラムの崩壊アウトされ、このような状況は、我々が見たくないです。

イベントキューの問題を解決するために:

以下は、イベントキューの設計方法を図で表現されます。

IMG

  もちろん、数字は唯一の3つの操作ですが、あなたが望むなら、あなたは、このような読み取りなど、より操作を、設計することができ、あなたはコンテンツの操作に対応するコピーエントリ情報とエントリに細分化することができます。

このような設計の後、それはある程度の排除にGUIの動作を中断する問題である(そのような私たちは私たちの訪問に遭遇した一種のようなオブジェクトの問題のデストラクタです)。

  Qtの中で、私たちは書くことができます(ConnectionViewこのオブジェクト私はそのエントリ上と言われています)

class ItemsOpsBase
    {
    public:
        virtual void doOperation(ConnectionView *view) = 0;
        virtual ~ItemsOpsBase() = default;
    };
    
    class DeleteItem : public ItemsOpsBase
    {
    public:
        DeleteItem(qintptr target,qint32 connectionIndex)
            :ItemsOpsBase(), _target(target),_connectionIndex(connectionIndex){ }
        
        void doOperation(ConnectionView *view)override;
        ~DeleteItem() = default;
    private:
        qintptr _target;
        qint32 _connectionIndex;
    };
    
    class UpdatePulse :public ItemsOpsBase
    {
    public:
        UpdatePulse(qintptr descriptor,qint32 currentTime)
            :ItemsOpsBase(), _descriptor(descriptor),_currentTime(currentTime){  }
        
        void doOperation(ConnectionView *view)override;
        ~UpdatePulse() = default;
    private:
        qintptr _descriptor;
        qint32 _currentTime;
    };

class UpdateRemark : public ItemsOpsBase
    {
    public:
        UpdateRemark(qintptr descriptor, const QString &remark)
            : ItemsOpsBase(),_remark(remark),_descriptor(descriptor){  }
        
        void doOperation(ConnectionView *view)override;
        ~UpdateRemark() = default;
    private:
        QString _remark;
        qintptr _descriptor;
    };
    
    class TestConnection : public ItemsOpsBase
    {
    public:
        void doOperation(ConnectionView *view)override;
    };
class TestConnectionProducer : public QThread
    {
    public:
        void run()override;
    };
    
    class CopySelectedItemInformProducer :  public QThread
    {
    public:
        void run()override;
    };
    
    class DisconnectTargetsProducer : public QThread
    {
    public:
        void run()override;
    };
    
    class DeleteItemProducer :public QThread
    {
    public:
        DeleteItemProducer(qintptr target, qint32 connectionIndex)
            : QThread(),_target(target),_connectionIndex(connectionIndex) { }
        void run()override;
    private:
        qintptr _target;
        qint32 _connectionIndex;
    };
    
    class UpdatePulseProducer :public QThread
    {
    public:
        UpdatePulseProducer(qintptr descriptor, qint32 currentTime)
            :QThread(),_descriptor(descriptor),_currentTime(currentTime){  }
    protected:  
        void run()override;
    private:
        qintptr _descriptor;
        qint32 _currentTime;
    };
    
    class UpdateRemarkProducer : public QThread
    {
    public:
        UpdateRemarkProducer(qintptr descriptor, const QString &remark)
            :QThread(),_remark(remark),_descriptor(descriptor){ }
    protected:   
        void run()override;
    private:
        QString _remark;
        qintptr _descriptor;
    };
class ConsumerHelper :public QThread
    {
    public:
        ConsumerHelper(ConnectionView *view)
            :QThread(),_view(view){ }
        ~ConsumerHelper();
    protected:
        void run() override;
    private:
        ConnectionView *_view;
        
        ConsumerHelper(const ConsumerHelper &other) = delete;
        ConsumerHelper(const ConsumerHelper &&other) = delete;
        ConsumerHelper &operator=(const ConsumerHelper &other) = delete;
    };

  そして、キューミューテックスコード:

static QQueue<QSharedPointer<ItemsOpsBase>> &opQueue()
{
       static QQueue<QSharedPointer<ItemsOpsBase>> queue;
       return queue;
}
    
static QSharedPointer<ItemsOpsBase> endOperation;

static QMutex &opQueueLock()
{
       static QMutex mutex;
       return mutex;
}
static QWaitCondition &opQueueIsAvailable()
{
       static QWaitCondition flag;
       return flag;
}

  ConsumerHelperは、キューの動きを監視してきた消費者スレッドであるあなたは、特定の操作を必要とするとき、我々は、オブジェクトのスレッドの動作をトリガすることができ、(キューに参加するために、対応する操作は、なぜ私が相互に容易にするために、スレッドを開く必要があります次のような排除)、私は削除操作が必要になります。

  コードの操作を削除します。

void DeleteItem::doOperation(ConnectionView *view)
    {
        qRegisterMetaType<qintptr>("qintptr");
        qRegisterMetaType<TcpConnectionHandler *>("TcpConnectionHandler *");
        QMetaObject::invokeMethod(view, "deleteConnection",Qt::QueuedConnection, Q_ARG(qintptr, _target), Q_ARG(qint32, _connectionIndex));
    }
void DeleteItemProducer::run()
    {
        QSharedPointer<ItemsOpsBase> op = QSharedPointer<ItemsOpsBase>(new DeleteItem(_target,_connectionIndex));
        
        QMutexLocker locker(&opQueueLock());
        opQueue().enqueue(op);
        opQueueIsAvailable().wakeOne();
    }

消費者は、コードをスレッド化:

void ConsumerHelper::run()
    {
        forever
        {
            QSharedPointer<ItemsOpsBase> opPointer;
            
            {
                QMutexLocker locker(&opQueueLock());
                
                if (opQueue().isEmpty())
                    opQueueIsAvailable().wait(&opQueueLock());
                opPointer = opQueue().dequeue();
                
                if (opPointer == endOperation)
                    break;
            }
            {
                if(!opPointer.isNull())
                    opPointer->doOperation(_view);
            }
        }
    } 

    ConsumerHelper::~ConsumerHelper()
    {
        {
            QMutexLocker locker(&opQueueLock());
            while(!opQueue().isEmpty())
                opQueue().dequeue();
            
            opQueue().enqueue(endOperation);
            opQueueIsAvailable().wakeOne();
        }
        
        wait();//注意这里是wait在次线程上的
    }

  この時間は、私はちょうど削除操作の代わりに使用する必要があります。

DeleteItemProducer *deleteItemProducer = new DeleteItemProducer(target,index);
connect(deleteItemProducer, &QThread::finished, deleteItemProducer, &QThread::deleteLater);
deleteItemProducer->start();

おすすめ

転載: www.cnblogs.com/schips/p/12536427.html