Hi Jan, Interesting problem!
I think I see what you mean: There's no way to combine the completion of an event plus saving its value as an atomic operation, except by putting the synchronization in its own thread. But if you put the synchronization in its own thread, then there's no way to prevent that thread's synchronization when a consumer synchronization (i.e., one that is waiting for the thread's result) picks a different event than the one represented by the thread. It's easy to make a complete+save combination atomic if it's built into the scheduler. So, I can easily imagine adding a simpler primitive, `once-evt`. The event OE created by `(once-evt E)` could save the first result produced by E, but not attempt to have only a single wait on E. That is, if OE1 is synchronized in multiple threads, then it would be like synchronizing E in multiple threads, but only the first result from E will be saved. Unfortunately, `once-evt` isn't enough to implement `memoize-evt`. The troublesome case is then thread T1 is synchronizing on OE1, T1 gets suspended, and T2 starts waiting on OE1. In that case, you'd like T2 to take over the wait, even if it means restarting E. You can detect that T1 is suspended and have T2 start waiting on E, but there's no way to cancel the wait of E in T1. Building `memoize-evt` into the core doesn't the avoid the need to, at some level, cancel T1's wait on E. I'll keep thinking about it, but it looks like that would require deep changes to the scheduler. Would the simpler `once-evt` work in your situation, or do you need the guarantee that only one wait of E happens at a time? Matthew At Wed, 28 Jan 2015 13:49:51 +0100, Jan Dvořák wrote: > Hi, > > I would like to ask for another extension of the Racket's event handling > system. A `memoize-evt` constructor with following semantics: > > Given a base event E_b, memoize-evt will produce a memoizing event E_m. > Synchronizing on E_m from any number of threads will block until a > single value is produced by E_b. This value is then stored inside the > E_m. From that moment on, E_m will always be immediately ready for > synchronization and produce the stored value in all waiting threads. > > The single-threaded implementation is a trivial guard-evt + replace-evt > + (wrap-evt always-evt) combo, but for thread-safety a temporary thread > would be needed to wait for the base event and the solution would have > different semantics then rest of the event system. > > A lower-level approach would also be possible; create something along > the lines of a dynamic-wind-evt that would, with some cleverness, allow > for generic thread-safe events via locking. Or create a locked-wrap-evt > constructor that will not be ready until it's handler finishes. > > Hoping that I am not being too bothersome, > from Prague with thanks, > Jan Dvorak _________________________ Racket Developers list: http://lists.racket-lang.org/dev