Why pthread_rdlock doesn`t downgrade the lock?
Just because you think a particular behavior or mode of operation would be reasonable does not mean you can rely on it to be the actual behavior or mode of operation. Often there are multiple plausible alternatives. Occasionally you will run into designs that just don't make sense to you or are objectively poor. It is your duty as programmer to rely on documentation instead of on assumptions.
In particular, this interface is specified by POSIX, which says:
The calling thread acquires the read lock if a writer does not hold the lock and there are no writers blocked on the lock.
(emphasis added)
If the calling thread holds the write lock then a writer does hold the lock. What's more:
[... I]f the read lock is not acquired, the calling thread shall block until it can acquire the lock. The calling thread may deadlock if at the time the call is made it holds a write lock.
The specs also describe among the error conditions:
[EDEADLK]
A deadlock condition was detected or the current thread already owns the read-write lock for writing.
, which would be an allowed alternative to actually deadlocking under those circumstances.
Therefore, there is no good reason for a programmer who has done their due diligence to assume that they could "downgrade the lock" from a write lock to a read lock by calling pthread_rwlock_rdlock()
without first releasing the write lock by calling pthread_rwlock_unlock()
. The same applies to upgrading from a read lock to a write lock.
With respect to your code, then,
The (1) acquires the lock,
Yes, if successful. In particular, it acquires the write lock.
then (2) lock it into read-mode.
A read-write lock is better thought of as a bundle of two separate locks than as a single, modal lock. pthread_rwlock_rdlock()
attempts to acquire the read lock of the pair. This will not succeed while any thread holds the write lock, including the one trying to obtain the read lock.
I suppose that (3) will block the current thread, but actually it hasn`t. The program goes well.
How do you know it doesn't block? If it blocked for only a few milliseconds then you probably wouldn't notice. Perhaps you meant that you supposed (3) would deadlock but then it's not clear to me why you thought you could downgrade a lock but could not upgrade one. (In fact, you cannot do either).
The manual doesn`t explain the downgrading or upgrading stuffs.
Exactly. The manual does not describe upgrading or downgrading a rwlock that is already held. On the contrary, although it doesn't explicitly say you can't, it does contain language that should at least make you doubt whether you can do it with your particular pthreads implementation, and that should convey that it is not portable to rely on doing so. But if you have a write lock and want a read lock instead then you can of course unlock the rwlock and then, separately, acquire the read lock. Likewise for going the other direction. That does afford the possibility that another thread acquires one side or the other of the lock in between, but if you cannot abide that then you need to prevent it by some other means.
Did I ignore something?
It looks like you may have ignored that attempts to acquire either side of a rwlock can fail, as almost all calls to system interfaces can do. You need to check the return values of your function calls to confirm that they succeeded and / or recognize when they fail. In your particular case, I suspect that some of your lock acquisition calls are failing, possibly with EDEADLK
.
If your "why?" is a request for a rationale for this design then I'm afraid you're out of luck. The POSIX system interfaces rationale document does devote a few words to pthreads read/write locks, but it does not speak directly to this question, so we can only speculate about why the rwlock interface is designed as it is in this regard.
If you want to rationalize it, though, you can imagine that a read-write lock is not a unitary object, but rather two separate locks bundled together and managed cooperatively. That doesn't necessarily imply that you couldn't have lock downgrades, but perhaps it makes that prospect seem less natural. You can also observe that POSIX maintains acquire / release consistency across a variety of synchronization objects.