Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/corelib/thread/qreadwritelock.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||||||||
2 | ** | - | ||||||||||||||||||
3 | ** Copyright (C) 2016 The Qt Company Ltd. | - | ||||||||||||||||||
4 | ** Copyright (C) 2016 Intel Corporation. | - | ||||||||||||||||||
5 | ** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com> | - | ||||||||||||||||||
6 | ** Contact: https://www.qt.io/licensing/ | - | ||||||||||||||||||
7 | ** | - | ||||||||||||||||||
8 | ** This file is part of the QtCore module of the Qt Toolkit. | - | ||||||||||||||||||
9 | ** | - | ||||||||||||||||||
10 | ** $QT_BEGIN_LICENSE:LGPL$ | - | ||||||||||||||||||
11 | ** Commercial License Usage | - | ||||||||||||||||||
12 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||||||||
13 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||||||||
14 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||||||||
15 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||||||||
16 | ** and conditions see https://www.qt.io/terms-conditions. For further | - | ||||||||||||||||||
17 | ** information use the contact form at https://www.qt.io/contact-us. | - | ||||||||||||||||||
18 | ** | - | ||||||||||||||||||
19 | ** GNU Lesser General Public License Usage | - | ||||||||||||||||||
20 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||||||||
21 | ** General Public License version 3 as published by the Free Software | - | ||||||||||||||||||
22 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | - | ||||||||||||||||||
23 | ** packaging of this file. Please review the following information to | - | ||||||||||||||||||
24 | ** ensure the GNU Lesser General Public License version 3 requirements | - | ||||||||||||||||||
25 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | - | ||||||||||||||||||
26 | ** | - | ||||||||||||||||||
27 | ** GNU General Public License Usage | - | ||||||||||||||||||
28 | ** Alternatively, this file may be used under the terms of the GNU | - | ||||||||||||||||||
29 | ** General Public License version 2.0 or (at your option) the GNU General | - | ||||||||||||||||||
30 | ** Public license version 3 or any later version approved by the KDE Free | - | ||||||||||||||||||
31 | ** Qt Foundation. The licenses are as published by the Free Software | - | ||||||||||||||||||
32 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | - | ||||||||||||||||||
33 | ** included in the packaging of this file. Please review the following | - | ||||||||||||||||||
34 | ** information to ensure the GNU General Public License requirements will | - | ||||||||||||||||||
35 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | - | ||||||||||||||||||
36 | ** https://www.gnu.org/licenses/gpl-3.0.html. | - | ||||||||||||||||||
37 | ** | - | ||||||||||||||||||
38 | ** $QT_END_LICENSE$ | - | ||||||||||||||||||
39 | ** | - | ||||||||||||||||||
40 | ****************************************************************************/ | - | ||||||||||||||||||
41 | - | |||||||||||||||||||
42 | #include "qplatformdefs.h" | - | ||||||||||||||||||
43 | #include "qreadwritelock.h" | - | ||||||||||||||||||
44 | - | |||||||||||||||||||
45 | #ifndef QT_NO_THREAD | - | ||||||||||||||||||
46 | #include "qmutex.h" | - | ||||||||||||||||||
47 | #include "qthread.h" | - | ||||||||||||||||||
48 | #include "qwaitcondition.h" | - | ||||||||||||||||||
49 | #include "qreadwritelock_p.h" | - | ||||||||||||||||||
50 | #include "qelapsedtimer.h" | - | ||||||||||||||||||
51 | #include "private/qfreelist_p.h" | - | ||||||||||||||||||
52 | - | |||||||||||||||||||
53 | QT_BEGIN_NAMESPACE | - | ||||||||||||||||||
54 | - | |||||||||||||||||||
55 | /* | - | ||||||||||||||||||
56 | * Implementation details of QReadWriteLock: | - | ||||||||||||||||||
57 | * | - | ||||||||||||||||||
58 | * Depending on the valued of d_ptr, the lock is in the following state: | - | ||||||||||||||||||
59 | * - when d_ptr == 0x0: Unlocked (no readers, no writers) and non-recursive. | - | ||||||||||||||||||
60 | * - when d_ptr & 0x1: If the least significant bit is set, we are locked for read. | - | ||||||||||||||||||
61 | * In that case, d_ptr>>4 represents the number of reading threads minus 1. No writers | - | ||||||||||||||||||
62 | * are waiting, and the lock is not recursive. | - | ||||||||||||||||||
63 | * - when d_ptr == 0x2: We are locked for write and nobody is waiting. (no contention) | - | ||||||||||||||||||
64 | * - In any other case, d_ptr points to an actual QReadWriteLockPrivate. | - | ||||||||||||||||||
65 | */ | - | ||||||||||||||||||
66 | - | |||||||||||||||||||
67 | namespace { | - | ||||||||||||||||||
68 | enum { | - | ||||||||||||||||||
69 | StateMask = 0x3, | - | ||||||||||||||||||
70 | StateLockedForRead = 0x1, | - | ||||||||||||||||||
71 | StateLockedForWrite = 0x2, | - | ||||||||||||||||||
72 | }; | - | ||||||||||||||||||
73 | const auto dummyLockedForRead = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForRead)); | - | ||||||||||||||||||
74 | const auto dummyLockedForWrite = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForWrite)); | - | ||||||||||||||||||
75 | inline bool isUncontendedLocked(const QReadWriteLockPrivate *d) | - | ||||||||||||||||||
76 | { executed 317361 times by 523 tests: return quintptr(d) & StateMask; }return quintptr(d) & StateMask; Executed by:
executed 317361 times by 523 tests: return quintptr(d) & StateMask; Executed by:
| 317361 | ||||||||||||||||||
77 | } | - | ||||||||||||||||||
78 | - | |||||||||||||||||||
79 | /*! \class QReadWriteLock | - | ||||||||||||||||||
80 | \inmodule QtCore | - | ||||||||||||||||||
81 | \brief The QReadWriteLock class provides read-write locking. | - | ||||||||||||||||||
82 | - | |||||||||||||||||||
83 | \threadsafe | - | ||||||||||||||||||
84 | - | |||||||||||||||||||
85 | \ingroup thread | - | ||||||||||||||||||
86 | - | |||||||||||||||||||
87 | A read-write lock is a synchronization tool for protecting | - | ||||||||||||||||||
88 | resources that can be accessed for reading and writing. This type | - | ||||||||||||||||||
89 | of lock is useful if you want to allow multiple threads to have | - | ||||||||||||||||||
90 | simultaneous read-only access, but as soon as one thread wants to | - | ||||||||||||||||||
91 | write to the resource, all other threads must be blocked until | - | ||||||||||||||||||
92 | the writing is complete. | - | ||||||||||||||||||
93 | - | |||||||||||||||||||
94 | In many cases, QReadWriteLock is a direct competitor to QMutex. | - | ||||||||||||||||||
95 | QReadWriteLock is a good choice if there are many concurrent | - | ||||||||||||||||||
96 | reads and writing occurs infrequently. | - | ||||||||||||||||||
97 | - | |||||||||||||||||||
98 | Example: | - | ||||||||||||||||||
99 | - | |||||||||||||||||||
100 | \snippet code/src_corelib_thread_qreadwritelock.cpp 0 | - | ||||||||||||||||||
101 | - | |||||||||||||||||||
102 | To ensure that writers aren't blocked forever by readers, readers | - | ||||||||||||||||||
103 | attempting to obtain a lock will not succeed if there is a blocked | - | ||||||||||||||||||
104 | writer waiting for access, even if the lock is currently only | - | ||||||||||||||||||
105 | accessed by other readers. Also, if the lock is accessed by a | - | ||||||||||||||||||
106 | writer and another writer comes in, that writer will have | - | ||||||||||||||||||
107 | priority over any readers that might also be waiting. | - | ||||||||||||||||||
108 | - | |||||||||||||||||||
109 | Like QMutex, a QReadWriteLock can be recursively locked by the | - | ||||||||||||||||||
110 | same thread when constructed with \l{QReadWriteLock::Recursive} as | - | ||||||||||||||||||
111 | \l{QReadWriteLock::RecursionMode}. In such cases, | - | ||||||||||||||||||
112 | unlock() must be called the same number of times lockForWrite() or | - | ||||||||||||||||||
113 | lockForRead() was called. Note that the lock type cannot be | - | ||||||||||||||||||
114 | changed when trying to lock recursively, i.e. it is not possible | - | ||||||||||||||||||
115 | to lock for reading in a thread that already has locked for | - | ||||||||||||||||||
116 | writing (and vice versa). | - | ||||||||||||||||||
117 | - | |||||||||||||||||||
118 | \sa QReadLocker, QWriteLocker, QMutex, QSemaphore | - | ||||||||||||||||||
119 | */ | - | ||||||||||||||||||
120 | - | |||||||||||||||||||
121 | /*! | - | ||||||||||||||||||
122 | \enum QReadWriteLock::RecursionMode | - | ||||||||||||||||||
123 | \since 4.4 | - | ||||||||||||||||||
124 | - | |||||||||||||||||||
125 | \value Recursive In this mode, a thread can lock the same | - | ||||||||||||||||||
126 | QReadWriteLock multiple times. The QReadWriteLock won't be unlocked | - | ||||||||||||||||||
127 | until a corresponding number of unlock() calls have been made. | - | ||||||||||||||||||
128 | - | |||||||||||||||||||
129 | \value NonRecursive In this mode, a thread may only lock a | - | ||||||||||||||||||
130 | QReadWriteLock once. | - | ||||||||||||||||||
131 | - | |||||||||||||||||||
132 | \sa QReadWriteLock() | - | ||||||||||||||||||
133 | */ | - | ||||||||||||||||||
134 | - | |||||||||||||||||||
135 | /*! | - | ||||||||||||||||||
136 | \since 4.4 | - | ||||||||||||||||||
137 | - | |||||||||||||||||||
138 | Constructs a QReadWriteLock object in the given \a recursionMode. | - | ||||||||||||||||||
139 | - | |||||||||||||||||||
140 | The default recursion mode is NonRecursive. | - | ||||||||||||||||||
141 | - | |||||||||||||||||||
142 | \sa lockForRead(), lockForWrite(), RecursionMode | - | ||||||||||||||||||
143 | */ | - | ||||||||||||||||||
144 | QReadWriteLock::QReadWriteLock(RecursionMode recursionMode) | - | ||||||||||||||||||
145 | : d_ptr(recursionMode == Recursive ? new QReadWriteLockPrivate(true) : nullptr) | - | ||||||||||||||||||
146 | { | - | ||||||||||||||||||
147 | Q_ASSERT_X(!(quintptr(d_ptr.load()) & StateMask), "QReadWriteLock::QReadWriteLock", "bad d_ptr alignment"); | - | ||||||||||||||||||
148 | } executed 42232 times by 296 tests: end of block Executed by:
| 42232 | ||||||||||||||||||
149 | - | |||||||||||||||||||
150 | /*! | - | ||||||||||||||||||
151 | Destroys the QReadWriteLock object. | - | ||||||||||||||||||
152 | - | |||||||||||||||||||
153 | \warning Destroying a read-write lock that is in use may result | - | ||||||||||||||||||
154 | in undefined behavior. | - | ||||||||||||||||||
155 | */ | - | ||||||||||||||||||
156 | QReadWriteLock::~QReadWriteLock() | - | ||||||||||||||||||
157 | { | - | ||||||||||||||||||
158 | auto d = d_ptr.load(); | - | ||||||||||||||||||
159 | if (isUncontendedLocked(d)) {
| 0-43112 | ||||||||||||||||||
160 | qWarning("QReadWriteLock: destroying locked QReadWriteLock"); | - | ||||||||||||||||||
161 | return; never executed: return; | 0 | ||||||||||||||||||
162 | } | - | ||||||||||||||||||
163 | delete d; | - | ||||||||||||||||||
164 | } executed 43112 times by 519 tests: end of block Executed by:
| 43112 | ||||||||||||||||||
165 | - | |||||||||||||||||||
166 | /*! | - | ||||||||||||||||||
167 | Locks the lock for reading. This function will block the current | - | ||||||||||||||||||
168 | thread if another thread has locked for writing. | - | ||||||||||||||||||
169 | - | |||||||||||||||||||
170 | It is not possible to lock for read if the thread already has | - | ||||||||||||||||||
171 | locked for write. | - | ||||||||||||||||||
172 | - | |||||||||||||||||||
173 | \sa unlock(), lockForWrite(), tryLockForRead() | - | ||||||||||||||||||
174 | */ | - | ||||||||||||||||||
175 | void QReadWriteLock::lockForRead() | - | ||||||||||||||||||
176 | { | - | ||||||||||||||||||
177 | if (d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead))
| 143670-1557572 | ||||||||||||||||||
178 | return; executed 1557572 times by 355 tests: return; Executed by:
| 1557572 | ||||||||||||||||||
179 | tryLockForRead(-1); | - | ||||||||||||||||||
180 | } executed 143670 times by 10 tests: end of block Executed by:
| 143670 | ||||||||||||||||||
181 | - | |||||||||||||||||||
182 | /*! | - | ||||||||||||||||||
183 | Attempts to lock for reading. If the lock was obtained, this | - | ||||||||||||||||||
184 | function returns \c true, otherwise it returns \c false instead of | - | ||||||||||||||||||
185 | waiting for the lock to become available, i.e. it does not block. | - | ||||||||||||||||||
186 | - | |||||||||||||||||||
187 | The lock attempt will fail if another thread has locked for | - | ||||||||||||||||||
188 | writing. | - | ||||||||||||||||||
189 | - | |||||||||||||||||||
190 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||
191 | before another thread can successfully lock it for writing. | - | ||||||||||||||||||
192 | - | |||||||||||||||||||
193 | It is not possible to lock for read if the thread already has | - | ||||||||||||||||||
194 | locked for write. | - | ||||||||||||||||||
195 | - | |||||||||||||||||||
196 | \sa unlock(), lockForRead() | - | ||||||||||||||||||
197 | */ | - | ||||||||||||||||||
198 | bool QReadWriteLock::tryLockForRead() | - | ||||||||||||||||||
199 | { | - | ||||||||||||||||||
200 | return tryLockForRead(0); executed 43 times by 2 tests: return tryLockForRead(0); Executed by:
| 43 | ||||||||||||||||||
201 | } | - | ||||||||||||||||||
202 | - | |||||||||||||||||||
203 | /*! \overload | - | ||||||||||||||||||
204 | - | |||||||||||||||||||
205 | Attempts to lock for reading. This function returns \c true if the | - | ||||||||||||||||||
206 | lock was obtained; otherwise it returns \c false. If another thread | - | ||||||||||||||||||
207 | has locked for writing, this function will wait for at most \a | - | ||||||||||||||||||
208 | timeout milliseconds for the lock to become available. | - | ||||||||||||||||||
209 | - | |||||||||||||||||||
210 | Note: Passing a negative number as the \a timeout is equivalent to | - | ||||||||||||||||||
211 | calling lockForRead(), i.e. this function will wait forever until | - | ||||||||||||||||||
212 | lock can be locked for reading when \a timeout is negative. | - | ||||||||||||||||||
213 | - | |||||||||||||||||||
214 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||
215 | before another thread can successfully lock it for writing. | - | ||||||||||||||||||
216 | - | |||||||||||||||||||
217 | It is not possible to lock for read if the thread already has | - | ||||||||||||||||||
218 | locked for write. | - | ||||||||||||||||||
219 | - | |||||||||||||||||||
220 | \sa unlock(), lockForRead() | - | ||||||||||||||||||
221 | */ | - | ||||||||||||||||||
222 | bool QReadWriteLock::tryLockForRead(int timeout) | - | ||||||||||||||||||
223 | { | - | ||||||||||||||||||
224 | // Fast case: non contended: | - | ||||||||||||||||||
225 | QReadWriteLockPrivate *d; | - | ||||||||||||||||||
226 | if (d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead, d))
| 4-143712 | ||||||||||||||||||
227 | return true; executed 4 times by 1 test: return true; Executed by:
| 4 | ||||||||||||||||||
228 | - | |||||||||||||||||||
229 | while (true) { | - | ||||||||||||||||||
230 | if (d == 0) {
| 0-143712 | ||||||||||||||||||
231 | if (!d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead, d))
| 0 | ||||||||||||||||||
232 | continue; never executed: continue; | 0 | ||||||||||||||||||
233 | return true; never executed: return true; | 0 | ||||||||||||||||||
234 | } | - | ||||||||||||||||||
235 | - | |||||||||||||||||||
236 | if ((quintptr(d) & StateMask) == StateLockedForRead) {
| 11198-132514 | ||||||||||||||||||
237 | // locked for read, increase the counter | - | ||||||||||||||||||
238 | const auto val = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d) + (1U<<4)); | - | ||||||||||||||||||
239 | Q_ASSERT_X(quintptr(val) > (1U<<4), "QReadWriteLock::tryLockForRead()", | - | ||||||||||||||||||
240 | "Overflow in lock counter"); | - | ||||||||||||||||||
241 | if (!d_ptr.testAndSetAcquire(d, val, d))
| 0-11198 | ||||||||||||||||||
242 | continue; never executed: continue; | 0 | ||||||||||||||||||
243 | return true; executed 11198 times by 6 tests: return true; Executed by:
| 11198 | ||||||||||||||||||
244 | } | - | ||||||||||||||||||
245 | - | |||||||||||||||||||
246 | if (d == dummyLockedForWrite) {
| 42-132472 | ||||||||||||||||||
247 | if (!timeout)
| 2-40 | ||||||||||||||||||
248 | return false; executed 2 times by 1 test: return false; Executed by:
| 2 | ||||||||||||||||||
249 | - | |||||||||||||||||||
250 | // locked for write, assign a d_ptr and wait. | - | ||||||||||||||||||
251 | auto val = QReadWriteLockPrivate::allocate(); | - | ||||||||||||||||||
252 | val->writerCount = 1; | - | ||||||||||||||||||
253 | if (!d_ptr.testAndSetOrdered(d, val, d)) {
| 0-40 | ||||||||||||||||||
254 | val->writerCount = 0; | - | ||||||||||||||||||
255 | val->release(); | - | ||||||||||||||||||
256 | continue; never executed: continue; | 0 | ||||||||||||||||||
257 | } | - | ||||||||||||||||||
258 | d = val; | - | ||||||||||||||||||
259 | } executed 40 times by 3 tests: end of block Executed by:
| 40 | ||||||||||||||||||
260 | Q_ASSERT(!isUncontendedLocked(d)); | - | ||||||||||||||||||
261 | // d is an actual pointer; | - | ||||||||||||||||||
262 | - | |||||||||||||||||||
263 | if (d->recursive)
| 126-132386 | ||||||||||||||||||
264 | return d->recursiveLockForRead(timeout); executed 126 times by 5 tests: return d->recursiveLockForRead(timeout); Executed by:
| 126 | ||||||||||||||||||
265 | - | |||||||||||||||||||
266 | QMutexLocker lock(&d->mutex); | - | ||||||||||||||||||
267 | if (d != d_ptr.load()) {
| 0-132386 | ||||||||||||||||||
268 | // d_ptr has changed: this QReadWriteLock was unlocked before we had | - | ||||||||||||||||||
269 | // time to lock d->mutex. | - | ||||||||||||||||||
270 | // We are holding a lock to a mutex within a QReadWriteLockPrivate | - | ||||||||||||||||||
271 | // that is already released (or even is already re-used). That's ok | - | ||||||||||||||||||
272 | // because the QFreeList never frees them. | - | ||||||||||||||||||
273 | // Just unlock d->mutex (at the end of the scope) and retry. | - | ||||||||||||||||||
274 | d = d_ptr.loadAcquire(); | - | ||||||||||||||||||
275 | continue; never executed: continue; | 0 | ||||||||||||||||||
276 | } | - | ||||||||||||||||||
277 | return d->lockForRead(timeout); executed 132386 times by 3 tests: return d->lockForRead(timeout); Executed by:
| 132386 | ||||||||||||||||||
278 | } | - | ||||||||||||||||||
279 | } never executed: end of block | 0 | ||||||||||||||||||
280 | - | |||||||||||||||||||
281 | /*! | - | ||||||||||||||||||
282 | Locks the lock for writing. This function will block the current | - | ||||||||||||||||||
283 | thread if another thread (including the current) has locked for | - | ||||||||||||||||||
284 | reading or writing (unless the lock has been created using the | - | ||||||||||||||||||
285 | \l{QReadWriteLock::Recursive} mode). | - | ||||||||||||||||||
286 | - | |||||||||||||||||||
287 | It is not possible to lock for write if the thread already has | - | ||||||||||||||||||
288 | locked for read. | - | ||||||||||||||||||
289 | - | |||||||||||||||||||
290 | \sa unlock(), lockForRead(), tryLockForWrite() | - | ||||||||||||||||||
291 | */ | - | ||||||||||||||||||
292 | void QReadWriteLock::lockForWrite() | - | ||||||||||||||||||
293 | { | - | ||||||||||||||||||
294 | tryLockForWrite(-1); | - | ||||||||||||||||||
295 | } executed 348346 times by 568 tests: end of block Executed by:
| 348346 | ||||||||||||||||||
296 | - | |||||||||||||||||||
297 | /*! | - | ||||||||||||||||||
298 | Attempts to lock for writing. If the lock was obtained, this | - | ||||||||||||||||||
299 | function returns \c true; otherwise, it returns \c false immediately. | - | ||||||||||||||||||
300 | - | |||||||||||||||||||
301 | The lock attempt will fail if another thread has locked for | - | ||||||||||||||||||
302 | reading or writing. | - | ||||||||||||||||||
303 | - | |||||||||||||||||||
304 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||
305 | before another thread can successfully lock it. | - | ||||||||||||||||||
306 | - | |||||||||||||||||||
307 | It is not possible to lock for write if the thread already has | - | ||||||||||||||||||
308 | locked for read. | - | ||||||||||||||||||
309 | - | |||||||||||||||||||
310 | \sa unlock(), lockForWrite() | - | ||||||||||||||||||
311 | */ | - | ||||||||||||||||||
312 | bool QReadWriteLock::tryLockForWrite() | - | ||||||||||||||||||
313 | { | - | ||||||||||||||||||
314 | return tryLockForWrite(0); executed 62 times by 4 tests: return tryLockForWrite(0); Executed by:
| 62 | ||||||||||||||||||
315 | } | - | ||||||||||||||||||
316 | - | |||||||||||||||||||
317 | /*! \overload | - | ||||||||||||||||||
318 | - | |||||||||||||||||||
319 | Attempts to lock for writing. This function returns \c true if the | - | ||||||||||||||||||
320 | lock was obtained; otherwise it returns \c false. If another thread | - | ||||||||||||||||||
321 | has locked for reading or writing, this function will wait for at | - | ||||||||||||||||||
322 | most \a timeout milliseconds for the lock to become available. | - | ||||||||||||||||||
323 | - | |||||||||||||||||||
324 | Note: Passing a negative number as the \a timeout is equivalent to | - | ||||||||||||||||||
325 | calling lockForWrite(), i.e. this function will wait forever until | - | ||||||||||||||||||
326 | lock can be locked for writing when \a timeout is negative. | - | ||||||||||||||||||
327 | - | |||||||||||||||||||
328 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||
329 | before another thread can successfully lock it. | - | ||||||||||||||||||
330 | - | |||||||||||||||||||
331 | It is not possible to lock for write if the thread already has | - | ||||||||||||||||||
332 | locked for read. | - | ||||||||||||||||||
333 | - | |||||||||||||||||||
334 | \sa unlock(), lockForWrite() | - | ||||||||||||||||||
335 | */ | - | ||||||||||||||||||
336 | bool QReadWriteLock::tryLockForWrite(int timeout) | - | ||||||||||||||||||
337 | { | - | ||||||||||||||||||
338 | // Fast case: non contended: | - | ||||||||||||||||||
339 | QReadWriteLockPrivate *d; | - | ||||||||||||||||||
340 | if (d_ptr.testAndSetAcquire(nullptr, dummyLockedForWrite, d))
| 3057-345353 | ||||||||||||||||||
341 | return true; executed 345353 times by 565 tests: return true; Executed by:
| 345353 | ||||||||||||||||||
342 | - | |||||||||||||||||||
343 | while (true) { | - | ||||||||||||||||||
344 | if (d == 0) {
| 0-3057 | ||||||||||||||||||
345 | if (!d_ptr.testAndSetAcquire(d, dummyLockedForWrite, d))
| 0 | ||||||||||||||||||
346 | continue; never executed: continue; | 0 | ||||||||||||||||||
347 | return true; never executed: return true; | 0 | ||||||||||||||||||
348 | } | - | ||||||||||||||||||
349 | - | |||||||||||||||||||
350 | if (isUncontendedLocked(d)) {
| 88-2969 | ||||||||||||||||||
351 | if (!timeout)
| 10-78 | ||||||||||||||||||
352 | return false; executed 10 times by 3 tests: return false; Executed by:
| 10 | ||||||||||||||||||
353 | - | |||||||||||||||||||
354 | // locked for either read or write, assign a d_ptr and wait. | - | ||||||||||||||||||
355 | auto val = QReadWriteLockPrivate::allocate(); | - | ||||||||||||||||||
356 | if (d == dummyLockedForWrite)
| 24-54 | ||||||||||||||||||
357 | val->writerCount = 1; executed 54 times by 3 tests: val->writerCount = 1; Executed by:
| 54 | ||||||||||||||||||
358 | else | - | ||||||||||||||||||
359 | val->readerCount = (quintptr(d) >> 4) + 1; executed 24 times by 3 tests: val->readerCount = (quintptr(d) >> 4) + 1; Executed by:
| 24 | ||||||||||||||||||
360 | if (!d_ptr.testAndSetOrdered(d, val, d)) {
| 0-78 | ||||||||||||||||||
361 | val->writerCount = val->readerCount = 0; | - | ||||||||||||||||||
362 | val->release(); | - | ||||||||||||||||||
363 | continue; never executed: continue; | 0 | ||||||||||||||||||
364 | } | - | ||||||||||||||||||
365 | d = val; | - | ||||||||||||||||||
366 | } executed 78 times by 3 tests: end of block Executed by:
| 78 | ||||||||||||||||||
367 | Q_ASSERT(!isUncontendedLocked(d)); | - | ||||||||||||||||||
368 | // d is an actual pointer; | - | ||||||||||||||||||
369 | - | |||||||||||||||||||
370 | if (d->recursive)
| 76-2971 | ||||||||||||||||||
371 | return d->recursiveLockForWrite(timeout); executed 76 times by 8 tests: return d->recursiveLockForWrite(timeout); Executed by:
| 76 | ||||||||||||||||||
372 | - | |||||||||||||||||||
373 | QMutexLocker lock(&d->mutex); | - | ||||||||||||||||||
374 | if (d != d_ptr.load()) {
| 0-2971 | ||||||||||||||||||
375 | // The mutex was unlocked before we had time to lock the mutex. | - | ||||||||||||||||||
376 | // We are holding to a mutex within a QReadWriteLockPrivate that is already released | - | ||||||||||||||||||
377 | // (or even is already re-used) but that's ok because the QFreeList never frees them. | - | ||||||||||||||||||
378 | d = d_ptr.loadAcquire(); | - | ||||||||||||||||||
379 | continue; never executed: continue; | 0 | ||||||||||||||||||
380 | } | - | ||||||||||||||||||
381 | return d->lockForWrite(timeout); executed 2971 times by 3 tests: return d->lockForWrite(timeout); Executed by:
| 2971 | ||||||||||||||||||
382 | } | - | ||||||||||||||||||
383 | } never executed: end of block | 0 | ||||||||||||||||||
384 | - | |||||||||||||||||||
385 | /*! | - | ||||||||||||||||||
386 | Unlocks the lock. | - | ||||||||||||||||||
387 | - | |||||||||||||||||||
388 | Attempting to unlock a lock that is not locked is an error, and will result | - | ||||||||||||||||||
389 | in program termination. | - | ||||||||||||||||||
390 | - | |||||||||||||||||||
391 | \sa lockForRead(), lockForWrite(), tryLockForRead(), tryLockForWrite() | - | ||||||||||||||||||
392 | */ | - | ||||||||||||||||||
393 | void QReadWriteLock::unlock() | - | ||||||||||||||||||
394 | { | - | ||||||||||||||||||
395 | QReadWriteLockPrivate *d = d_ptr.load(); | - | ||||||||||||||||||
396 | while (true) { | - | ||||||||||||||||||
397 | Q_ASSERT_X(d, "QReadWriteLock::unlock()", "Cannot unlock an unlocked lock"); | - | ||||||||||||||||||
398 | - | |||||||||||||||||||
399 | // Fast case: no contention: (no waiters, no other readers) | - | ||||||||||||||||||
400 | if (quintptr(d) <= 2) { // 1 or 2 (StateLockedForRead or StateLockedForWrite)
| 146830-1902811 | ||||||||||||||||||
401 | if (!d_ptr.testAndSetRelease(d, nullptr, d))
| 1-1902810 | ||||||||||||||||||
402 | continue; executed 1 time by 1 test: continue; Executed by:
| 1 | ||||||||||||||||||
403 | return; executed 1902810 times by 572 tests: return; Executed by:
| 1902810 | ||||||||||||||||||
404 | } | - | ||||||||||||||||||
405 | - | |||||||||||||||||||
406 | if ((quintptr(d) & StateMask) == StateLockedForRead) {
| 11197-135633 | ||||||||||||||||||
407 | Q_ASSERT(quintptr(d) > (1U<<4)); //otherwise that would be the fast case | - | ||||||||||||||||||
408 | // Just decrease the reader's count. | - | ||||||||||||||||||
409 | auto val = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d) - (1U<<4)); | - | ||||||||||||||||||
410 | if (!d_ptr.testAndSetRelease(d, val, d))
| 0-11197 | ||||||||||||||||||
411 | continue; never executed: continue; | 0 | ||||||||||||||||||
412 | return; executed 11197 times by 6 tests: return; Executed by:
| 11197 | ||||||||||||||||||
413 | } | - | ||||||||||||||||||
414 | - | |||||||||||||||||||
415 | Q_ASSERT(!isUncontendedLocked(d)); | - | ||||||||||||||||||
416 | - | |||||||||||||||||||
417 | if (d->recursive) {
| 159-135474 | ||||||||||||||||||
418 | d->recursiveUnlock(); | - | ||||||||||||||||||
419 | return; executed 159 times by 8 tests: return; Executed by:
| 159 | ||||||||||||||||||
420 | } | - | ||||||||||||||||||
421 | - | |||||||||||||||||||
422 | QMutexLocker locker(&d->mutex); | - | ||||||||||||||||||
423 | if (d->writerCount) {
| 3064-132410 | ||||||||||||||||||
424 | Q_ASSERT(d->writerCount == 1); | - | ||||||||||||||||||
425 | Q_ASSERT(d->readerCount == 0); | - | ||||||||||||||||||
426 | d->writerCount = 0; | - | ||||||||||||||||||
427 | } else { executed 3064 times by 3 tests: end of block Executed by:
| 3064 | ||||||||||||||||||
428 | Q_ASSERT(d->readerCount > 0); | - | ||||||||||||||||||
429 | d->readerCount--; | - | ||||||||||||||||||
430 | if (d->readerCount > 0)
| 265-132145 | ||||||||||||||||||
431 | return; executed 132145 times by 1 test: return; Executed by:
| 132145 | ||||||||||||||||||
432 | } executed 265 times by 3 tests: end of block Executed by:
| 265 | ||||||||||||||||||
433 | - | |||||||||||||||||||
434 | if (d->waitingReaders || d->waitingWriters) {
| 118-3002 | ||||||||||||||||||
435 | d->unlock(); | - | ||||||||||||||||||
436 | } else { executed 3211 times by 3 tests: end of block Executed by:
| 3211 | ||||||||||||||||||
437 | Q_ASSERT(d_ptr.load() == d); // should not change when we still hold the mutex | - | ||||||||||||||||||
438 | d_ptr.storeRelease(nullptr); | - | ||||||||||||||||||
439 | d->release(); | - | ||||||||||||||||||
440 | } executed 118 times by 3 tests: end of block Executed by:
| 118 | ||||||||||||||||||
441 | return; executed 3329 times by 3 tests: return; Executed by:
| 3329 | ||||||||||||||||||
442 | } | - | ||||||||||||||||||
443 | } never executed: end of block | 0 | ||||||||||||||||||
444 | - | |||||||||||||||||||
445 | /*! \internal Helper for QWaitCondition::wait */ | - | ||||||||||||||||||
446 | QReadWriteLock::StateForWaitCondition QReadWriteLock::stateForWaitCondition() const | - | ||||||||||||||||||
447 | { | - | ||||||||||||||||||
448 | QReadWriteLockPrivate *d = d_ptr.load(); | - | ||||||||||||||||||
449 | switch (quintptr(d) & StateMask) { | - | ||||||||||||||||||
450 | case StateLockedForRead: return LockedForRead; executed 25 times by 1 test: return LockedForRead; Executed by:
executed 25 times by 1 test: case StateLockedForRead: Executed by:
| 25 | ||||||||||||||||||
451 | case StateLockedForWrite: return LockedForWrite; executed 108 times by 1 test: return LockedForWrite; Executed by:
executed 108 times by 1 test: case StateLockedForWrite: Executed by:
| 108 | ||||||||||||||||||
452 | } | - | ||||||||||||||||||
453 | - | |||||||||||||||||||
454 | if (!d)
| 0-141 | ||||||||||||||||||
455 | return Unlocked; never executed: return Unlocked; | 0 | ||||||||||||||||||
456 | if (d->writerCount > 1)
| 0-141 | ||||||||||||||||||
457 | return RecursivelyLocked; never executed: return RecursivelyLocked; | 0 | ||||||||||||||||||
458 | else if (d->writerCount == 1)
| 18-123 | ||||||||||||||||||
459 | return LockedForWrite; executed 123 times by 1 test: return LockedForWrite; Executed by:
| 123 | ||||||||||||||||||
460 | return LockedForRead; executed 18 times by 1 test: return LockedForRead; Executed by:
| 18 | ||||||||||||||||||
461 | - | |||||||||||||||||||
462 | } | - | ||||||||||||||||||
463 | - | |||||||||||||||||||
464 | bool QReadWriteLockPrivate::lockForRead(int timeout) | - | ||||||||||||||||||
465 | { | - | ||||||||||||||||||
466 | Q_ASSERT(!mutex.tryLock()); // mutex must be locked when entering this function | - | ||||||||||||||||||
467 | - | |||||||||||||||||||
468 | QElapsedTimer t; | - | ||||||||||||||||||
469 | if (timeout > 0)
| 1-132492 | ||||||||||||||||||
470 | t.start(); executed 1 time by 1 test: t.start(); Executed by:
| 1 | ||||||||||||||||||
471 | - | |||||||||||||||||||
472 | while (waitingWriters || writerCount) {
| 72-132543 | ||||||||||||||||||
473 | if (timeout == 0)
| 21-437 | ||||||||||||||||||
474 | return false; executed 21 times by 2 tests: return false; Executed by:
| 21 | ||||||||||||||||||
475 | if (timeout > 0) {
| 8-429 | ||||||||||||||||||
476 | auto elapsed = t.elapsed(); | - | ||||||||||||||||||
477 | if (elapsed > timeout)
| 1-7 | ||||||||||||||||||
478 | return false; executed 1 time by 1 test: return false; Executed by:
| 1 | ||||||||||||||||||
479 | waitingReaders++; | - | ||||||||||||||||||
480 | readerCond.wait(&mutex, timeout - elapsed); | - | ||||||||||||||||||
481 | } else { executed 7 times by 1 test: end of block Executed by:
| 7 | ||||||||||||||||||
482 | waitingReaders++; | - | ||||||||||||||||||
483 | readerCond.wait(&mutex); | - | ||||||||||||||||||
484 | } executed 429 times by 3 tests: end of block Executed by:
| 429 | ||||||||||||||||||
485 | waitingReaders--; | - | ||||||||||||||||||
486 | } executed 436 times by 3 tests: end of block Executed by:
| 436 | ||||||||||||||||||
487 | readerCount++; | - | ||||||||||||||||||
488 | Q_ASSERT(writerCount == 0); | - | ||||||||||||||||||
489 | return true; executed 132471 times by 6 tests: return true; Executed by:
| 132471 | ||||||||||||||||||
490 | } | - | ||||||||||||||||||
491 | - | |||||||||||||||||||
492 | bool QReadWriteLockPrivate::lockForWrite(int timeout) | - | ||||||||||||||||||
493 | { | - | ||||||||||||||||||
494 | Q_ASSERT(!mutex.tryLock()); // mutex must be locked when entering this function | - | ||||||||||||||||||
495 | - | |||||||||||||||||||
496 | QElapsedTimer t; | - | ||||||||||||||||||
497 | if (timeout > 0)
| 1-3034 | ||||||||||||||||||
498 | t.start(); executed 1 time by 1 test: t.start(); Executed by:
| 1 | ||||||||||||||||||
499 | - | |||||||||||||||||||
500 | while (readerCount || writerCount) {
| 74-3276 | ||||||||||||||||||
501 | if (timeout == 0)
| 22-316 | ||||||||||||||||||
502 | return false; executed 22 times by 2 tests: return false; Executed by:
| 22 | ||||||||||||||||||
503 | if (timeout > 0) {
| 8-308 | ||||||||||||||||||
504 | auto elapsed = t.elapsed(); | - | ||||||||||||||||||
505 | if (elapsed > timeout) {
| 1-7 | ||||||||||||||||||
506 | if (waitingReaders && !waitingWriters && !writerCount) {
| 0-1 | ||||||||||||||||||
507 | // We timed out and now there is no more writers or waiting writers, but some | - | ||||||||||||||||||
508 | // readers were queueud (probably because of us). Wake the waiting readers. | - | ||||||||||||||||||
509 | readerCond.wakeAll(); | - | ||||||||||||||||||
510 | } never executed: end of block | 0 | ||||||||||||||||||
511 | return false; executed 1 time by 1 test: return false; Executed by:
| 1 | ||||||||||||||||||
512 | } | - | ||||||||||||||||||
513 | waitingWriters++; | - | ||||||||||||||||||
514 | writerCond.wait(&mutex, timeout - elapsed); | - | ||||||||||||||||||
515 | } else { executed 7 times by 1 test: end of block Executed by:
| 7 | ||||||||||||||||||
516 | waitingWriters++; | - | ||||||||||||||||||
517 | writerCond.wait(&mutex); | - | ||||||||||||||||||
518 | } executed 308 times by 3 tests: end of block Executed by:
| 308 | ||||||||||||||||||
519 | waitingWriters--; | - | ||||||||||||||||||
520 | } executed 315 times by 3 tests: end of block Executed by:
| 315 | ||||||||||||||||||
521 | - | |||||||||||||||||||
522 | Q_ASSERT(writerCount == 0); | - | ||||||||||||||||||
523 | Q_ASSERT(readerCount == 0); | - | ||||||||||||||||||
524 | writerCount = 1; | - | ||||||||||||||||||
525 | return true; executed 3012 times by 9 tests: return true; Executed by:
| 3012 | ||||||||||||||||||
526 | } | - | ||||||||||||||||||
527 | - | |||||||||||||||||||
528 | void QReadWriteLockPrivate::unlock() | - | ||||||||||||||||||
529 | { | - | ||||||||||||||||||
530 | Q_ASSERT(!mutex.tryLock()); // mutex must be locked when entering this function | - | ||||||||||||||||||
531 | if (waitingWriters)
| 417-2922 | ||||||||||||||||||
532 | writerCond.wakeOne(); executed 2922 times by 3 tests: writerCond.wakeOne(); Executed by:
| 2922 | ||||||||||||||||||
533 | else if (waitingReaders)
| 127-290 | ||||||||||||||||||
534 | readerCond.wakeAll(); executed 290 times by 3 tests: readerCond.wakeAll(); Executed by:
| 290 | ||||||||||||||||||
535 | } executed 3339 times by 9 tests: end of block Executed by:
| 3339 | ||||||||||||||||||
536 | - | |||||||||||||||||||
537 | bool QReadWriteLockPrivate::recursiveLockForRead(int timeout) | - | ||||||||||||||||||
538 | { | - | ||||||||||||||||||
539 | Q_ASSERT(recursive); | - | ||||||||||||||||||
540 | QMutexLocker lock(&mutex); | - | ||||||||||||||||||
541 | - | |||||||||||||||||||
542 | Qt::HANDLE self = QThread::currentThreadId(); | - | ||||||||||||||||||
543 | - | |||||||||||||||||||
544 | auto it = currentReaders.find(self); | - | ||||||||||||||||||
545 | if (it != currentReaders.end()) {
| 19-107 | ||||||||||||||||||
546 | ++it.value(); | - | ||||||||||||||||||
547 | return true; executed 19 times by 4 tests: return true; Executed by:
| 19 | ||||||||||||||||||
548 | } | - | ||||||||||||||||||
549 | - | |||||||||||||||||||
550 | if (!lockForRead(timeout))
| 21-86 | ||||||||||||||||||
551 | return false; executed 21 times by 2 tests: return false; Executed by:
| 21 | ||||||||||||||||||
552 | - | |||||||||||||||||||
553 | currentReaders.insert(self, 1); | - | ||||||||||||||||||
554 | return true; executed 86 times by 5 tests: return true; Executed by:
| 86 | ||||||||||||||||||
555 | } | - | ||||||||||||||||||
556 | - | |||||||||||||||||||
557 | bool QReadWriteLockPrivate::recursiveLockForWrite(int timeout) | - | ||||||||||||||||||
558 | { | - | ||||||||||||||||||
559 | Q_ASSERT(recursive); | - | ||||||||||||||||||
560 | QMutexLocker lock(&mutex); | - | ||||||||||||||||||
561 | - | |||||||||||||||||||
562 | Qt::HANDLE self = QThread::currentThreadId(); | - | ||||||||||||||||||
563 | if (currentWriter == self) {
| 12-64 | ||||||||||||||||||
564 | writerCount++; | - | ||||||||||||||||||
565 | return true; executed 12 times by 2 tests: return true; Executed by:
| 12 | ||||||||||||||||||
566 | } | - | ||||||||||||||||||
567 | - | |||||||||||||||||||
568 | if (!lockForWrite(timeout))
| 22-42 | ||||||||||||||||||
569 | return false; executed 22 times by 2 tests: return false; Executed by:
| 22 | ||||||||||||||||||
570 | - | |||||||||||||||||||
571 | currentWriter = self; | - | ||||||||||||||||||
572 | return true; executed 42 times by 8 tests: return true; Executed by:
| 42 | ||||||||||||||||||
573 | } | - | ||||||||||||||||||
574 | - | |||||||||||||||||||
575 | void QReadWriteLockPrivate::recursiveUnlock() | - | ||||||||||||||||||
576 | { | - | ||||||||||||||||||
577 | Q_ASSERT(recursive); | - | ||||||||||||||||||
578 | QMutexLocker lock(&mutex); | - | ||||||||||||||||||
579 | - | |||||||||||||||||||
580 | Qt::HANDLE self = QThread::currentThreadId(); | - | ||||||||||||||||||
581 | if (self == currentWriter) {
| 54-105 | ||||||||||||||||||
582 | if (--writerCount > 0)
| 12-42 | ||||||||||||||||||
583 | return; executed 12 times by 2 tests: return; Executed by:
| 12 | ||||||||||||||||||
584 | currentWriter = 0; | - | ||||||||||||||||||
585 | } else { executed 42 times by 8 tests: end of block Executed by:
| 42 | ||||||||||||||||||
586 | auto it = currentReaders.find(self); | - | ||||||||||||||||||
587 | if (it == currentReaders.end()) {
| 0-105 | ||||||||||||||||||
588 | qWarning("QReadWriteLock::unlock: unlocking from a thread that did not lock"); | - | ||||||||||||||||||
589 | return; never executed: return; | 0 | ||||||||||||||||||
590 | } else { | - | ||||||||||||||||||
591 | if (--it.value() <= 0) {
| 19-86 | ||||||||||||||||||
592 | currentReaders.erase(it); | - | ||||||||||||||||||
593 | readerCount--; | - | ||||||||||||||||||
594 | } executed 86 times by 5 tests: end of block Executed by:
| 86 | ||||||||||||||||||
595 | if (readerCount)
| 19-86 | ||||||||||||||||||
596 | return; executed 19 times by 4 tests: return; Executed by:
| 19 | ||||||||||||||||||
597 | } executed 86 times by 5 tests: end of block Executed by:
| 86 | ||||||||||||||||||
598 | } | - | ||||||||||||||||||
599 | - | |||||||||||||||||||
600 | unlock(); | - | ||||||||||||||||||
601 | } executed 128 times by 8 tests: end of block Executed by:
| 128 | ||||||||||||||||||
602 | - | |||||||||||||||||||
603 | // The freelist management | - | ||||||||||||||||||
604 | namespace { | - | ||||||||||||||||||
605 | struct FreeListConstants : QFreeListDefaultConstants { | - | ||||||||||||||||||
606 | enum { BlockCount = 4, MaxIndex=0xffff }; | - | ||||||||||||||||||
607 | static const int Sizes[BlockCount]; | - | ||||||||||||||||||
608 | }; | - | ||||||||||||||||||
609 | const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = { | - | ||||||||||||||||||
610 | 16, | - | ||||||||||||||||||
611 | 128, | - | ||||||||||||||||||
612 | 1024, | - | ||||||||||||||||||
613 | FreeListConstants::MaxIndex - (16 + 128 + 1024) | - | ||||||||||||||||||
614 | }; | - | ||||||||||||||||||
615 | - | |||||||||||||||||||
616 | typedef QFreeList<QReadWriteLockPrivate, FreeListConstants> FreeList; | - | ||||||||||||||||||
617 | Q_GLOBAL_STATIC(FreeList, freelist); executed 3 times by 3 tests: end of block Executed by:
executed 3 times by 3 tests: guard.store(QtGlobalStatic::Destroyed); Executed by:
executed 354 times by 3 tests: return &holder.value; Executed by:
| 0-354 | ||||||||||||||||||
618 | } | - | ||||||||||||||||||
619 | - | |||||||||||||||||||
620 | QReadWriteLockPrivate *QReadWriteLockPrivate::allocate() | - | ||||||||||||||||||
621 | { | - | ||||||||||||||||||
622 | int i = freelist->next(); | - | ||||||||||||||||||
623 | QReadWriteLockPrivate *d = &(*freelist)[i]; | - | ||||||||||||||||||
624 | d->id = i; | - | ||||||||||||||||||
625 | Q_ASSERT(!d->recursive); | - | ||||||||||||||||||
626 | Q_ASSERT(!d->waitingReaders && !d->waitingReaders && !d->readerCount && !d->writerCount); | - | ||||||||||||||||||
627 | return d; executed 118 times by 3 tests: return d; Executed by:
| 118 | ||||||||||||||||||
628 | } | - | ||||||||||||||||||
629 | - | |||||||||||||||||||
630 | void QReadWriteLockPrivate::release() | - | ||||||||||||||||||
631 | { | - | ||||||||||||||||||
632 | Q_ASSERT(!recursive); | - | ||||||||||||||||||
633 | Q_ASSERT(!waitingReaders && !waitingReaders && !readerCount && !writerCount); | - | ||||||||||||||||||
634 | freelist->release(id); | - | ||||||||||||||||||
635 | } executed 118 times by 3 tests: end of block Executed by:
| 118 | ||||||||||||||||||
636 | - | |||||||||||||||||||
637 | /*! | - | ||||||||||||||||||
638 | \class QReadLocker | - | ||||||||||||||||||
639 | \inmodule QtCore | - | ||||||||||||||||||
640 | \brief The QReadLocker class is a convenience class that | - | ||||||||||||||||||
641 | simplifies locking and unlocking read-write locks for read access. | - | ||||||||||||||||||
642 | - | |||||||||||||||||||
643 | \threadsafe | - | ||||||||||||||||||
644 | - | |||||||||||||||||||
645 | \ingroup thread | - | ||||||||||||||||||
646 | - | |||||||||||||||||||
647 | The purpose of QReadLocker (and QWriteLocker) is to simplify | - | ||||||||||||||||||
648 | QReadWriteLock locking and unlocking. Locking and unlocking | - | ||||||||||||||||||
649 | statements or in exception handling code is error-prone and | - | ||||||||||||||||||
650 | difficult to debug. QReadLocker can be used in such situations | - | ||||||||||||||||||
651 | to ensure that the state of the lock is always well-defined. | - | ||||||||||||||||||
652 | - | |||||||||||||||||||
653 | Here's an example that uses QReadLocker to lock and unlock a | - | ||||||||||||||||||
654 | read-write lock for reading: | - | ||||||||||||||||||
655 | - | |||||||||||||||||||
656 | \snippet code/src_corelib_thread_qreadwritelock.cpp 1 | - | ||||||||||||||||||
657 | - | |||||||||||||||||||
658 | It is equivalent to the following code: | - | ||||||||||||||||||
659 | - | |||||||||||||||||||
660 | \snippet code/src_corelib_thread_qreadwritelock.cpp 2 | - | ||||||||||||||||||
661 | - | |||||||||||||||||||
662 | The QMutexLocker documentation shows examples where the use of a | - | ||||||||||||||||||
663 | locker object greatly simplifies programming. | - | ||||||||||||||||||
664 | - | |||||||||||||||||||
665 | \sa QWriteLocker, QReadWriteLock | - | ||||||||||||||||||
666 | */ | - | ||||||||||||||||||
667 | - | |||||||||||||||||||
668 | /*! | - | ||||||||||||||||||
669 | \fn QReadLocker::QReadLocker(QReadWriteLock *lock) | - | ||||||||||||||||||
670 | - | |||||||||||||||||||
671 | Constructs a QReadLocker and locks \a lock for reading. The lock | - | ||||||||||||||||||
672 | will be unlocked when the QReadLocker is destroyed. If \c lock is | - | ||||||||||||||||||
673 | zero, QReadLocker does nothing. | - | ||||||||||||||||||
674 | - | |||||||||||||||||||
675 | \sa QReadWriteLock::lockForRead() | - | ||||||||||||||||||
676 | */ | - | ||||||||||||||||||
677 | - | |||||||||||||||||||
678 | /*! | - | ||||||||||||||||||
679 | \fn QReadLocker::~QReadLocker() | - | ||||||||||||||||||
680 | - | |||||||||||||||||||
681 | Destroys the QReadLocker and unlocks the lock that was passed to | - | ||||||||||||||||||
682 | the constructor. | - | ||||||||||||||||||
683 | - | |||||||||||||||||||
684 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||
685 | */ | - | ||||||||||||||||||
686 | - | |||||||||||||||||||
687 | /*! | - | ||||||||||||||||||
688 | \fn void QReadLocker::unlock() | - | ||||||||||||||||||
689 | - | |||||||||||||||||||
690 | Unlocks the lock associated with this locker. | - | ||||||||||||||||||
691 | - | |||||||||||||||||||
692 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||
693 | */ | - | ||||||||||||||||||
694 | - | |||||||||||||||||||
695 | /*! | - | ||||||||||||||||||
696 | \fn void QReadLocker::relock() | - | ||||||||||||||||||
697 | - | |||||||||||||||||||
698 | Relocks an unlocked lock. | - | ||||||||||||||||||
699 | - | |||||||||||||||||||
700 | \sa unlock() | - | ||||||||||||||||||
701 | */ | - | ||||||||||||||||||
702 | - | |||||||||||||||||||
703 | /*! | - | ||||||||||||||||||
704 | \fn QReadWriteLock *QReadLocker::readWriteLock() const | - | ||||||||||||||||||
705 | - | |||||||||||||||||||
706 | Returns a pointer to the read-write lock that was passed | - | ||||||||||||||||||
707 | to the constructor. | - | ||||||||||||||||||
708 | */ | - | ||||||||||||||||||
709 | - | |||||||||||||||||||
710 | /*! | - | ||||||||||||||||||
711 | \class QWriteLocker | - | ||||||||||||||||||
712 | \inmodule QtCore | - | ||||||||||||||||||
713 | \brief The QWriteLocker class is a convenience class that | - | ||||||||||||||||||
714 | simplifies locking and unlocking read-write locks for write access. | - | ||||||||||||||||||
715 | - | |||||||||||||||||||
716 | \threadsafe | - | ||||||||||||||||||
717 | - | |||||||||||||||||||
718 | \ingroup thread | - | ||||||||||||||||||
719 | - | |||||||||||||||||||
720 | The purpose of QWriteLocker (and QReadLocker) is to simplify | - | ||||||||||||||||||
721 | QReadWriteLock locking and unlocking. Locking and unlocking | - | ||||||||||||||||||
722 | statements or in exception handling code is error-prone and | - | ||||||||||||||||||
723 | difficult to debug. QWriteLocker can be used in such situations | - | ||||||||||||||||||
724 | to ensure that the state of the lock is always well-defined. | - | ||||||||||||||||||
725 | - | |||||||||||||||||||
726 | Here's an example that uses QWriteLocker to lock and unlock a | - | ||||||||||||||||||
727 | read-write lock for writing: | - | ||||||||||||||||||
728 | - | |||||||||||||||||||
729 | \snippet code/src_corelib_thread_qreadwritelock.cpp 3 | - | ||||||||||||||||||
730 | - | |||||||||||||||||||
731 | It is equivalent to the following code: | - | ||||||||||||||||||
732 | - | |||||||||||||||||||
733 | \snippet code/src_corelib_thread_qreadwritelock.cpp 4 | - | ||||||||||||||||||
734 | - | |||||||||||||||||||
735 | The QMutexLocker documentation shows examples where the use of a | - | ||||||||||||||||||
736 | locker object greatly simplifies programming. | - | ||||||||||||||||||
737 | - | |||||||||||||||||||
738 | \sa QReadLocker, QReadWriteLock | - | ||||||||||||||||||
739 | */ | - | ||||||||||||||||||
740 | - | |||||||||||||||||||
741 | /*! | - | ||||||||||||||||||
742 | \fn QWriteLocker::QWriteLocker(QReadWriteLock *lock) | - | ||||||||||||||||||
743 | - | |||||||||||||||||||
744 | Constructs a QWriteLocker and locks \a lock for writing. The lock | - | ||||||||||||||||||
745 | will be unlocked when the QWriteLocker is destroyed. If \c lock is | - | ||||||||||||||||||
746 | zero, QWriteLocker does nothing. | - | ||||||||||||||||||
747 | - | |||||||||||||||||||
748 | \sa QReadWriteLock::lockForWrite() | - | ||||||||||||||||||
749 | */ | - | ||||||||||||||||||
750 | - | |||||||||||||||||||
751 | /*! | - | ||||||||||||||||||
752 | \fn QWriteLocker::~QWriteLocker() | - | ||||||||||||||||||
753 | - | |||||||||||||||||||
754 | Destroys the QWriteLocker and unlocks the lock that was passed to | - | ||||||||||||||||||
755 | the constructor. | - | ||||||||||||||||||
756 | - | |||||||||||||||||||
757 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||
758 | */ | - | ||||||||||||||||||
759 | - | |||||||||||||||||||
760 | /*! | - | ||||||||||||||||||
761 | \fn void QWriteLocker::unlock() | - | ||||||||||||||||||
762 | - | |||||||||||||||||||
763 | Unlocks the lock associated with this locker. | - | ||||||||||||||||||
764 | - | |||||||||||||||||||
765 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||
766 | */ | - | ||||||||||||||||||
767 | - | |||||||||||||||||||
768 | /*! | - | ||||||||||||||||||
769 | \fn void QWriteLocker::relock() | - | ||||||||||||||||||
770 | - | |||||||||||||||||||
771 | Relocks an unlocked lock. | - | ||||||||||||||||||
772 | - | |||||||||||||||||||
773 | \sa unlock() | - | ||||||||||||||||||
774 | */ | - | ||||||||||||||||||
775 | - | |||||||||||||||||||
776 | /*! | - | ||||||||||||||||||
777 | \fn QReadWriteLock *QWriteLocker::readWriteLock() const | - | ||||||||||||||||||
778 | - | |||||||||||||||||||
779 | Returns a pointer to the read-write lock that was passed | - | ||||||||||||||||||
780 | to the constructor. | - | ||||||||||||||||||
781 | */ | - | ||||||||||||||||||
782 | - | |||||||||||||||||||
783 | QT_END_NAMESPACE | - | ||||||||||||||||||
784 | - | |||||||||||||||||||
785 | #endif // QT_NO_THREAD | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |