File indexing completed on 2024-05-12 15:58:40
0001 /* 0002 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef KIS_SAFE_READ_LIST_H_ 0008 #define KIS_SAFE_READ_LIST_H_ 0009 0010 0011 #include <QList> 0012 0013 /** 0014 * \class KisSafeReadList 0015 * 0016 * This is a special wrapper around QList class 0017 * Q: Why is it needed? 0018 * A: It guarantees thread-safety of all the read requests to the list. 0019 * There is absolutely *no* guarantees for write requests though. 0020 * Q: Why pure QList cannot guarantee it? 0021 * A: First, Qt does not guarantee thread-safety for QList at all. 0022 * Second, QList is implicitly shared structure, therefore even 0023 * with read, but non-const requests (e.g. non-const QList::first()), 0024 * QList will perform internal write operations. That will lead to 0025 * a race condition in an environment with 3 and more threads. 0026 */ 0027 template<class T> class KisSafeReadList : private QList<T> { 0028 public: 0029 KisSafeReadList() {} 0030 0031 using typename QList<T>::const_iterator; 0032 0033 /** 0034 * All the methods of this class are split into two groups: 0035 * treadsafe and non-threadsafe. The methods from the first group 0036 * can be called concurrently with each other. The ones form 0037 * the other group can't be called concurrently (even with the 0038 * friends from the first group) and must have an exclusive 0039 * access to the list. 0040 */ 0041 0042 /** 0043 * The thread-safe group 0044 */ 0045 0046 inline const T& first() const { 0047 return QList<T>::first(); 0048 } 0049 0050 inline const T& last() const { 0051 return QList<T>::last(); 0052 } 0053 0054 inline const T& at(int i) const { 0055 return QList<T>::at(i); 0056 } 0057 0058 using QList<T>::constBegin; 0059 using QList<T>::constEnd; 0060 using QList<T>::isEmpty; 0061 using QList<T>::size; 0062 using QList<T>::indexOf; 0063 using QList<T>::contains; 0064 0065 /** 0066 * The non-thread-safe group 0067 */ 0068 0069 using QList<T>::append; 0070 using QList<T>::prepend; 0071 using QList<T>::insert; 0072 using QList<T>::removeAt; 0073 using QList<T>::clear; 0074 0075 private: 0076 Q_DISABLE_COPY(KisSafeReadList) 0077 }; 0078 0079 0080 #define FOREACH_SAFE(_iter, _container) \ 0081 for(_iter = _container.constBegin(); \ 0082 _iter != _container.constEnd(); \ 0083 _iter++) 0084 0085 0086 #endif /* KIS_SAFE_READ_LIST_H_ */