Qt 4.8
qreadwritelock.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
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 
50 #include "qreadwritelock_p.h"
51 
53 
121  :d(new QReadWriteLockPrivate(NonRecursive))
122 { }
123 
135  : d(new QReadWriteLockPrivate(recursionMode))
136 { }
137 
145 {
146  delete d;
147 }
148 
157 {
159 
160  Qt::HANDLE self = 0;
161  if (d->recursive) {
162  self = QThread::currentThreadId();
163 
165  if (it != d->currentReaders.end()) {
166  ++it.value();
167  ++d->accessCount;
168  Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::lockForRead()",
169  "Overflow in lock counter");
170  return;
171  }
172  }
173 
174  while (d->accessCount < 0 || d->waitingWriters) {
175  ++d->waitingReaders;
176  d->readerWait.wait(&d->mutex);
177  --d->waitingReaders;
178  }
179  if (d->recursive)
180  d->currentReaders.insert(self, 1);
181 
182  ++d->accessCount;
183  Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::lockForRead()", "Overflow in lock counter");
184 }
185 
200 {
202 
203  Qt::HANDLE self = 0;
204  if (d->recursive) {
205  self = QThread::currentThreadId();
206 
208  if (it != d->currentReaders.end()) {
209  ++it.value();
210  ++d->accessCount;
211  Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()",
212  "Overflow in lock counter");
213  return true;
214  }
215  }
216 
217  if (d->accessCount < 0)
218  return false;
219  if (d->recursive)
220  d->currentReaders.insert(self, 1);
221 
222  ++d->accessCount;
223  Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", "Overflow in lock counter");
224 
225  return true;
226 }
227 
248 {
250 
251  Qt::HANDLE self = 0;
252  if (d->recursive) {
253  self = QThread::currentThreadId();
254 
256  if (it != d->currentReaders.end()) {
257  ++it.value();
258  ++d->accessCount;
259  Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()",
260  "Overflow in lock counter");
261  return true;
262  }
263  }
264 
265  while (d->accessCount < 0 || d->waitingWriters) {
266  ++d->waitingReaders;
267  bool success = d->readerWait.wait(&d->mutex, timeout < 0 ? ULONG_MAX : ulong(timeout));
268  --d->waitingReaders;
269  if (!success)
270  return false;
271  }
272  if (d->recursive)
273  d->currentReaders.insert(self, 1);
274 
275  ++d->accessCount;
276  Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", "Overflow in lock counter");
277 
278  return true;
279 }
280 
288 {
290 
291  Qt::HANDLE self = 0;
292  if (d->recursive) {
293  self = QThread::currentThreadId();
294 
295  if (d->currentWriter == self) {
296  --d->accessCount;
297  Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()",
298  "Overflow in lock counter");
299  return;
300  }
301  }
302 
303  while (d->accessCount != 0) {
304  ++d->waitingWriters;
305  d->writerWait.wait(&d->mutex);
306  --d->waitingWriters;
307  }
308  if (d->recursive)
309  d->currentWriter = self;
310 
311  --d->accessCount;
312  Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()", "Overflow in lock counter");
313 }
314 
328 {
330 
331  Qt::HANDLE self = 0;
332  if (d->recursive) {
333  self = QThread::currentThreadId();
334 
335  if (d->currentWriter == self) {
336  --d->accessCount;
337  Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()",
338  "Overflow in lock counter");
339  return true;
340  }
341  }
342 
343  if (d->accessCount != 0)
344  return false;
345  if (d->recursive)
346  d->currentWriter = self;
347 
348  --d->accessCount;
349  Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::tryLockForWrite()",
350  "Overflow in lock counter");
351 
352  return true;
353 }
354 
375 {
377 
378  Qt::HANDLE self = 0;
379  if (d->recursive) {
380  self = QThread::currentThreadId();
381 
382  if (d->currentWriter == self) {
383  --d->accessCount;
384  Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()",
385  "Overflow in lock counter");
386  return true;
387  }
388  }
389 
390  while (d->accessCount != 0) {
391  ++d->waitingWriters;
392  bool success = d->writerWait.wait(&d->mutex, timeout < 0 ? ULONG_MAX : ulong(timeout));
393  --d->waitingWriters;
394 
395  if (!success)
396  return false;
397  }
398  if (d->recursive)
399  d->currentWriter = self;
400 
401  --d->accessCount;
402  Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::tryLockForWrite()",
403  "Overflow in lock counter");
404 
405  return true;
406 }
407 
417 {
419 
420  Q_ASSERT_X(d->accessCount != 0, "QReadWriteLock::unlock()", "Cannot unlock an unlocked lock");
421 
422  bool unlocked = false;
423  if (d->accessCount > 0) {
424  // releasing a read lock
425  if (d->recursive) {
428  if (it != d->currentReaders.end()) {
429  if (--it.value() <= 0)
430  d->currentReaders.erase(it);
431  }
432  }
433 
434  unlocked = --d->accessCount == 0;
435  } else if (d->accessCount < 0 && ++d->accessCount == 0) {
436  // released a write lock
437  unlocked = true;
438  d->currentWriter = 0;
439  }
440 
441  if (unlocked) {
442  if (d->waitingWriters) {
443  d->writerWait.wakeOne();
444  } else if (d->waitingReaders) {
445  d->readerWait.wakeAll();
446  }
447  }
448 }
449 
619 
620 #endif // QT_NO_THREAD
double d
Definition: qnumeric_p.h:62
QWaitCondition readerWait
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void unlock()
Unlocks the lock.
#define it(className, varName)
RecursionMode
QReadWriteLock multiple times and the mutex won&#39;t be unlocked until a corresponding number of unlock(...
bool tryLockForWrite()
Attempts to lock for writing.
QWaitCondition writerWait
void lockForWrite()
Locks the lock for writing.
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
bool tryLockForRead()
Attempts to lock for reading.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
QReadWriteLockPrivate * d
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
~QReadWriteLock()
Destroys the QReadWriteLock object.
void lockForRead()
Locks the lock for reading.
void * HANDLE
Definition: qnamespace.h:1671
unsigned long ulong
Definition: qglobal.h:997
bool wait(QMutex *mutex, unsigned long time=ULONG_MAX)
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes...
Definition: qmutex.h:101
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:467
QReadWriteLock()
Constructs a QReadWriteLock object in NonRecursive mode.
static QReadWriteLock lock
Definition: proxyconf.cpp:399
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition: qhash.h:865
QHash< Qt::HANDLE, int > currentReaders
iterator erase(iterator it)
Removes the (key, value) pair associated with the iterator pos from the hash, and returns an iterator...
Definition: qhash.h:827
static Qt::HANDLE currentThreadId()
Returns the thread handle of the currently executing thread.