Is there some deadlock possibility that I am missing when more than one thread acquire upgradable locks
TL;DR Yes, there is.
along with one (or more than one shared lock)
This doesn't really affect the deadlock possibility. Allowing shared locks while upgradeable lock exists is simply a feature of upgradeable locks, compared to an exclusive lock.
Let us first consider what upgradeable locks can be used for. We shall imagine the following situation:
- Several writer threads must check a condition (a read operation), then depending on that, modify the state
- Checking the condition is expensive
- The condition is satisfied rarely.
- Other threads also read the state.
Now, let us consider that we only have reader (shared) / writer (exclusive) locks, with no upgradeable lock:
- Writer takes an exclusive lock, and starts checking the condition
- Other threads must block while the expensive check operation is running - even if they only need to read.
It may be considered a disadvantage that the read portion of the check - write cycle blocks even reading threads. So, let us consider an alternative:
- Writer takes a shared lock, and starts checking the condition
- Other threads may also take shared locks
- Writer has checked the condition, and releases the read lock
- The condition was satisfied, and writer now tries to take an exclusive lock to proceed
Between 3. and 4. more than one writer may have finished checking the state - since they can check concurrently - and are now racing to take the exclusive lock. Only one can win, and others must block. While they are blocking, the winner is modifying the state.
In this situation, the writers waiting to grab the exclusive lock can not assume that the condition that they checked is valid any more! Another writer may have grabbed the lock before them, and the state has now been modified. They could ignore this, which might lead to undefined behaviour, depending on what the relation with the condition and the modification is. Or, they could check the condition again when they get the exclusive lock, which reverts us back to the first approach, except with potentially redundant checks that were useless because of the race. Either way, this approach is worse than the first one.
A solution for the situation above is the privileged read (upgradeable) lock:
- Writer takes a privileged lock, and starts checking the condition
- Other threads may take shared locks
- Writer has checked the condition which was satisfied, and upgrades to exclusive lock (must block until other locks have been released)
Let us consider a situation where multiple writers have been granted a privileged lock. They get to check the expensive condition concurrently, which is nice, but they still have a race to upgrade the lock. This time, the race results in a dead lock, because each writer hold the read lock, and wait for all read locks to be released before they can upgrade.
If the upgradeable lock is exclusive in relation to other upgradeable locks, then this dead lock cannot occur, and the race doesn't exist between the expensive check and the modification, but reader threads may still operate while the writer is checking.