jonboulle / clockwork

a fake clock for golang
Apache License 2.0
656 stars 57 forks source link

Add a new interface method: AfterTime #12

Closed maxtaco closed 1 year ago

maxtaco commented 7 years ago

Without this iterface, there is an unresolvable race condition with After vs. Advance. In one go routine, you might:

    deadline := /* some deadline in the future */;
    wait := deadline.Sub(fc.Now());
    select {
      case <-fc.After(wait):
    }

And in another, you might:

   fc.Advance(3)

The problem is that two go-routines might interleave arbitrarily. The solution is to compute the deadline and to call After atomically, but you can't do that without sleeping on a lock. I believe BlockUntil was partially invented to handle this problem, so that you could call Advance only after you know that the other go-routine was selecting on the After. But it can be quite challenging to figure out which parameter to pass to BlockUntil, especially if your code is happy to let old After calls just dangle until they expire (which otherwise isn't a problem).

The solution is just to add a new interface method, which is to write to a channel after a given time has been surpassed. This feature was basically available internally, but this PR makes it available publicly.

pierrebeaucamp commented 6 years ago

Fyi, #13 seems to fix the problem as well, as it's rewriting the After method to use timers. (At least it fixes the snippet from above)

muir commented 2 years ago

What's the status of this PR? Is there a reason it's been sitting for so long?

sagikazarmark commented 1 year ago

I'm not sure I like the idea of adding a non-standard method either. Although I'm not sure I understand the problem completely, sounds like #44 could be a fix for the above. Can you please try and let me know? Thanks!

sagikazarmark commented 1 year ago

Closing with no activity (recent changes may have provided a fix for the root cause).