mytex.RWLock recursive read lock

473 views
Skip to first unread message

Henrik Johansson

unread,
Sep 21, 2020, 6:16:12 AM9/21/20
to golang-nuts


Holds that this prohibits recursive read locks but why would it?
I understand that deadlocks can happen in case write locks are held in between the read locks
but why can't a goroutine issue several RLock calls?

It does actually work in the playground. https://play.golang.org/p/nOehJaeikxA
Is this simply a recommendation or should the docs be updated to clarify what this means?


Axel Wagner

unread,
Sep 21, 2020, 6:30:30 AM9/21/20
to Henrik Johansson, golang-nuts
I feel like the docs are pretty precise in what they say and why.

a blocked Lock call excludes new readers from acquiring the lock.

This means, the following could happen:
Goroutine 1 calls RLock, acquires a Read-Lock
Goroutine 2 calls Lock, blocking
Goroutine 1 calls RLock again, blocking (as no new read locks can be acquired while GR 2 is blocked).
Thus, you get a deadlock.

It also has a conditional on the section

If a goroutine holds a RWMutex for reading and another goroutine might call Lock […]
 
So if you know that no other goroutine might call Lock concurrently, then yes, you can call RLock twice. I can't really imagine a setting where you'd need an RWMutex and have that assurance and need recursive read locks. But there might be one.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAKOF696YKSGn3j%2BcyX7o0ukA7wnD2Kq19_QGefUoeMELUZGOWA%40mail.gmail.com.

Axel Wagner

unread,
Sep 21, 2020, 6:31:40 AM9/21/20
to Henrik Johansson, golang-nuts
(Note, FWIW, that in particular no write locks need to be *held*. It's enough for Lock to be *called*, it doesn't have to have returned yet)

Henrik Johansson

unread,
Sep 21, 2020, 6:49:13 AM9/21/20
to Axel Wagner, golang-nuts
Yes that's the canonical deadlock but doesn't the docs say
 
"In particular, this prohibits recursive read locking" 

which it doesn't unless you mix reads and writes.

I get that it's not advisable but it's not prohibited either or there would be a panic or something.

Axel Wagner

unread,
Sep 21, 2020, 6:59:41 AM9/21/20
to Henrik Johansson, golang-nuts
It only says that's excluded *if* you can have a concurrent Lock call.

Axel Wagner

unread,
Sep 21, 2020, 7:32:34 AM9/21/20
to Henrik Johansson, golang-nuts
To elaborate a bit: You are correct in that there is a slight syntactic ambiguity whether "this prohibits" refers to the entire sentence ("if another goroutine might call Lock, then a second RLock might not be acquired"), or only to the second half. I would argue the rest of the section makes it clear that the second version is intended - "a goroutine can not expect a second RLock to be acquired. This prohibits…".

But yes, it certainly can be argued that the ambiguity hides the possibility of nested RLocks when no other goroutine calls Lock. But even if then: Given that this would not be useful (an RLock without a concurrent Lock is functionally a no-op, AIUI), but *can* lead to incorrect code if applied improperly, that possibility doesn't seem worthwhile to advertise further.

So even if the docs are ambiguous, that hardly seems a problem.

andrey mirtchovski

unread,
Sep 21, 2020, 8:06:03 AM9/21/20
to Henrik Johansson, golang-nuts
> Is this simply a recommendation or should the docs be updated to clarify what this means?

perhaps the latter, although that question only seems to come up once
every two or so years. here's a good link:

https://groups.google.com/d/msg/golang-nuts/XqW1qcuZgKg/Ui3nQkeLV80J

the entire discussion where i found it is interesting:

https://groups.google.com/g/golang-nuts/c/vN5ncBdtkcA/m/zf6EydsFsxgJ

Henrik Johansson

unread,
Sep 21, 2020, 8:06:55 AM9/21/20
to Axel Wagner, golang-nuts
A lot can be argued ;)

Ambiguous docs however aren't generally good in any way. This came up as a consequence of real code being changed by a new very skilled developer and there was quite a bit discussion that could have been avoided with clearer docs.

We have sorted the issue I mostly wanted to confirm my suspicion wrt nested read locks.

Axel Wagner

unread,
Sep 21, 2020, 8:15:39 AM9/21/20
to Henrik Johansson, golang-nuts
On Mon, Sep 21, 2020 at 2:06 PM Henrik Johansson <dahan...@gmail.com> wrote:
Ambiguous docs however aren't generally good in any way. This came up as a consequence of real code being changed by a new very skilled developer and there was quite a bit discussion that could have been avoided with clearer docs.

I think it would be useful to be more explicit about the use-case then. As I said, I can't really fathom a situation where you'd *want* to do that and if you don't want it, I can't imagine how it would matter whether you can.

Axel Wagner

unread,
Sep 21, 2020, 8:26:46 AM9/21/20
to Henrik Johansson, golang-nuts
FTR, I still don't think the docs *are* ambiguous. The authoritative part is

If a goroutine holds a RWMutex for reading and another goroutine might call Lock, no goroutine should expect to be able to acquire a read lock until the initial read lock is released.

The rest is just additional explanation. This sentence alone is already sufficient to define the behavior.

Bryan C. Mills

unread,
Sep 22, 2020, 9:55:51 AM9/22/20
to golang-nuts
Note that a lock on a sync.Mutex or sync.RWMutex is not held by a specific goroutine: it can be locked by one goroutine, then communicated by some other means (such as being sent on a channel) and unlocked on a different goroutine. (See also https://golang.org/issue/9201.)

That is: these locks cannot be reentrant because they do not contain goroutine-specific metadata.

I read through the docs for this type again, and noticed that while the documentation for the Unlock method seems very clear on this point, the documentation for the type itself is not. (I filed https://golang.org/issue/41555, for which you are welcome to contribute a fix!)

Henrik Johansson

unread,
Sep 23, 2020, 11:26:08 AM9/23/20
to Bryan C. Mills, golang-nuts
This is funny, why isn't there a panic in this case? It clearly "works" as in it doesn't deadlock or panics assuming a write lock isn't somehow mixed incorrectly.


Bryan C. Mills

unread,
Sep 23, 2020, 11:51:15 AM9/23/20
to Henrik Johansson, golang-nuts
On Wed, Sep 23, 2020 at 11:25 AM Henrik Johansson <dahan...@gmail.com> wrote:
This is funny, why isn't there a panic in this case? It clearly "works" as in it doesn't deadlock or panics assuming a write lock isn't somehow mixed incorrectly.

Why would there be a panic? The behavior is well-defined and documented.
(Admittedly the documentation is a bit awkward, but documentation is hard to get exactly right.)
Reply all
Reply to author
Forward
0 new messages