Hi John, I think you're maybe missing the point.
The problem is not with TryLock, but with a race in your
implementation of TryUnlock.
I'll try to make it clearer.
This is your implementation plus some comments:
func TryUnlock(x *sync.Mutex) (success bool) {
if x.TryLock() {
x.Unlock()
// <<<< Another goroutine calls x.Lock, or x.TryLock: x is now locked.
return true // <<< true here is no longer meaningful,
because it should mean that the lock is unlocked, but another
interspersed goroutine locked it.
}
return false
}
On Mon, Jan 5, 2026 at 9:41 PM 'John Souvestre' via golang-nuts
<[email protected]> wrote:
>
> Hi Jan.
>
> > Time-of-check_to_time-of-use
>
> Yes, that's the underlying problem and that's why I used TryLock() to start
> with. It resolves the problem atomically. I would imagine that it
> determines if the mutex is locked, then locks it regardless, by doing
> something like a "swap". But by itself that isn't useful. It also returns
> the prior state of the mutex. Thus, the user knows both the prior state and
> the current state. The only exception I can think of would be if a
> TryUnlock() was used after it - and perhaps that's why Go chose to just offer
> the one and not both.
>
> The "if" inside TryUnlock() is acting on "time-of-check" information, and the
> mutex has been locked since then, and still is when TryUnlock()'s Unlock()
> executes.
>
> I think that this might be less confusing if we can all agree that the
> description of TryLock() was enhanced a bit. Instead of:
>
> "TryLock tries to lock m and reports whether it succeeded."
>
> I take "succeed" to mean that TryLock() found the lock unset, and set it.
> The opposite, to "fail" means that TryLock() found the lock set, so didn't
> have to set it.
>
> If so, I think this description would be clearer.
>
> "TryLock reports success if it locks m, else failure due to m being
> already locked. Either way, m ends up being locked.
>
> If we can agree to this much about TryLock()'s behavior, then consider that
> in my proposed TryUnlock(), action is only taken when my code verified that
> the mutex was unlocked to start with, and at that same time it was locked.
> So now I can safely execute an Unlock().
>
> John
>
> John Souvestre New Orleans LA, USA 504-454-0899
>
> -----Original Message-----
> From: Jan Mercl <[email protected]>
> Sent: 2026-01-05, Mon 12:12
> To: John Souvestre <[email protected]>
> Cc: Bushnell, Thomas <[email protected]>;
> [email protected]
> Subject: Re: [go-nuts] TryUnlock() and IsLocked() functions
>
> On Mon, Jan 5, 2026 at 7:10 PM 'John Souvestre' via golang-nuts
> <[email protected]> wrote:
>
> > So you are saying that TryLock()’s return (succeeded or failed) might not
> > be correct?
>
> See https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use
>
> --
> 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 [email protected].
> To view this discussion visit
> https://groups.google.com/d/msgid/golang-nuts/000e01dc7ea5%2436c8dfb0%24a45a9f10%24%40Souvestre.com.
--
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 [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/golang-nuts/CAGB3aiaQ3Xs1gHN%3D4E_VS2QiRiB6-gOZD2d5bDk76tmxmkNBrA%40mail.gmail.com.