Using QReadWriteLock
-
Hi,
The documentation for QReadWriteLock says "Note that the lock type cannot be changed when trying to lock recursively, i.e. it is not possible to lock for reading in a thread that already has locked for writing (and vice versa)."
I believe it makes perfect sense that the QReadWriteLock should not allow a recursive lock to change the lock type from reading to writing (to prevent deadlocks), but I don't see why the class should prevent my thread from obtaining a read lock if the current thread already has a write lock.
I would like to be able to write a function that obtains a write lock, and then enter another function that obtains a read lock, without unlocking the write lock.
Is there a way to do this without modifying the QReadWriteLock class?
Thanks,
Hans -
Use two QReadWriteLock objects?
One for writing (or a QWriteLocker) and one for reading (or a QReadLocker)? -
It will not wok, as a write lock is an exclusive lock:
- one write lock or multiple read locks.
Having a write lock and requiring a readlock in a sub function must create a deadlock.
If you already have a write lock, you have an exclusive lock, use it. -
tbscope: If somebody has a write lock you will not want anybody else to have a read lock, so splitting up the readwrite lock into two separate locks does not really make sense.
-
What is wrong about requesting a read lock on the very same thread that already has a write lock? Shouldn't that be allowed? Requesting a read-write lock succeeds, thus granting me implicit read access. Am I missing something?
-
Well, if you hold the write lock, then no requesting a read lock will block. I am sure logic to make ignore the read lock request could get added, but that introduces additional overhead that is almost always unnecessary.
Considering that locking is often in the critical path you do not want that overhead.
-
I know this thread is pretty old, but my issue is exactly as described by OP...
I had a class that was being used by multiple threads, and I needed to make it thread-safe... It has relatively lots of reads compared to writes, so I thought a QReadWriteLock would be great.
I went through all my (public) methods, and added in a QReadLocker(&rwLock) or QWriteLocker(&rwLock), depending if the method was const or not...
It certainly doesn't produce the most effective code, but it guarantees thread safety and allows multiple concurrent reads...But just like Volker, several methods that require a write lock will also call some public methods that are read-only that request a read lock.
Is the only way to make this correctly to make all public methods simply lock and call a private method like this? :@void DoSomething()
{
QWriteLock lock(&rwLock);
DoSomethingInternal(); //<-- This method doesn't lock
}@ -
[quote author="samapico" date="1335828210"]Is the only way to make this correctly to make all public methods simply lock and call a private method like this? :
@void DoSomething()
{
QWriteLock lock(&rwLock);
DoSomethingInternal(); //<-- This method doesn't lock
}@
[/quote]That would have been my first idea too.
Another idea would be using a [[doc:QThreadStorage]] to store a "hasWriteLock" flag for each thread.
Then something like this should be possible:
@QThreadStorage<bool> hasWriteLock;
void DoWriteAction()
{
QWriteLock lock(&rwLock);
hasWriteLock.setLocalData(true)/* Do stuff */
DoReadAction();
/* Do stuff */
hasWriteLock.setLocalData(false)
}void DoReadAction()
{
const bool needLock = (!(hasWriteLock.hasLocalData() && hasWriteLock.localData()));if(needLock) rwLock.lockForRead();
/* Do stuff */
if(needLock) rwLock.unlock();
}@ -
Hmmm, not all my threads are QThreads... I'm guessing QThreadStorage wouldn't work right for me? In fact, only the UI stuff runs in QThreads in my project, I think.