File indexing completed on 2024-05-12 15:58:25

0001 /*
0002  *  SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_LAZY_WAIT_CONDITION_H
0008 #define __KIS_LAZY_WAIT_CONDITION_H
0009 
0010 
0011 #include <QWaitCondition>
0012 
0013 /**
0014  * This class is used for catching a particular condition met.
0015  * We call it "lazy", because the decision about the condition is made
0016  * by the waiting thread itself. The other thread, "wakingup" one,
0017  * just points the former one the moments of time when the condition
0018  * *might* have been satisfied. This creates some limitations for
0019  * the condition (see a note in the end of the text).
0020  *
0021  * Usage pattern:
0022  *
0023  * Waiting thread:
0024  *
0025  * KisLazyWaitCondition condition;
0026  * condition.initWainting();   // (1)
0027  * while(!checkSatisfied()) {
0028  *     condition.wait();
0029  * }
0030  * condition.endWaiting();     // (2)
0031  *
0032  *
0033  * Wakingup thread:
0034  *
0035  * if(checkMightSatisfied()) {
0036  *     condition.wakeAll();
0037  * }
0038  *
0039  * If the condition is met and reported, it is guaranteed that
0040  * all the threads, those are currently running between
0041  * lines (1) and (2) will be waken up and leave the loop.
0042  *
0043  * NOTE:
0044  * The condition checkSatisfied() must not change it's state, until
0045  * all the waiting threads leave the waiting loop. This requirement
0046  * must be guaranteed by the user of this class
0047  */
0048 
0049 class KisLazyWaitCondition
0050 {
0051 public:
0052     KisLazyWaitCondition()
0053         : m_waitCounter(0),
0054           m_wakeupCounter(0)
0055     {
0056     }
0057 
0058     void initWaiting() {
0059         QMutexLocker locker(&m_mutex);
0060         if(!m_waitCounter) {
0061             m_wakeupCounter = 0;
0062         }
0063 
0064         m_waitCounter++;
0065     }
0066 
0067     void endWaiting() {
0068         QMutexLocker locker(&m_mutex);
0069         m_waitCounter--;
0070     }
0071 
0072     bool wait(unsigned long time = ULONG_MAX) {
0073         QMutexLocker locker(&m_mutex);
0074         bool result = true;
0075         if(!m_wakeupCounter) {
0076             result = m_condition.wait(&m_mutex, time);
0077         }
0078         if(result) {
0079             m_wakeupCounter--;
0080         }
0081         return result;
0082     }
0083 
0084     void wakeAll() {
0085         if(!m_waitCounter) return;
0086 
0087         QMutexLocker locker(&m_mutex);
0088         if(m_waitCounter) {
0089             m_wakeupCounter += m_waitCounter;
0090             m_condition.wakeAll();
0091         }
0092     }
0093 
0094     bool isSomeoneWaiting() {
0095         return m_waitCounter;
0096     }
0097 
0098 private:
0099     QMutex m_mutex;
0100     QWaitCondition m_condition;
0101     volatile int m_waitCounter;
0102     int m_wakeupCounter;
0103 };
0104 
0105 #endif /* __KIS_LAZY_WAIT_CONDITION_H */