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.

Reply via email to