Event is a synchronization object. An event has two states signaled and reset. A task may await for the event to enter the desired state, usually the signaled state. It is released once the state is entered. Releasing waiting tasks is called event notification. Programmatically controlled events can be set by a task into one of its states.

Task
Events
You are encouraged to solve this task according to the task description, using any language you may know.

In concurrent programming event also refers to a notification that some state has been reached through an asynchronous activity. The source of the event can be:

  • internal, from another task, programmatically;
  • external, from the hardware, such as user input, timer, etc. Signaling an event from the hardware is accomplished by means of hardware interrupts.

Event is a low-level synchronization mechanism. It neither identify the state that caused it signaled, nor the source of, nor who is the subject of notification. Events augmented by data and/or publisher-subscriber schemes are often referred as messages, signals etc.

In the context of general programming event-driven architecture refers to a design that deploy events in order to synchronize tasks with the asynchronous activities they must be aware of. The opposite approach is polling sometimes called busy waiting, when the synchronization is achieved by an explicit periodic querying the state of the activity. As the name suggests busy waiting consumes system resources even when the external activity does not change its state.

Event-driven architectures are widely used in GUI design and SCADA systems. They are flexible and have relatively short response times. At the same time event-driven architectures suffer to the problems related to their unpredictability. They face race condition, deadlocking, live locks and priority inversion. For this reason real-time systems tend to polling schemes, trading performance for predictability in the worst case scenario.

Variants of events

Manual-reset event

This event changes its state by an explicit request of a task. I.e. once signaled it remains in this state until it will be explicitly reset.

Pulse event

A pulse event when signaled releases all tasks awaiting it and then is automatically reset.

Sample implementations / APIs

Show how a manual-reset event can be implemented in the language or else use an API to a library that provides events. Write a program that waits 1s and then signals the event to a task waiting for the event.

Ada

Ada provides higher-level concurrency primitives, which are complete in the sense that they also allow implementations of the lower-level ones, like event. Here is an implementation of the manual-reset event.

The event interface: <lang ada>protected type Event is

  procedure Signal;
  procedure Reset;
  entry Wait;

private

  Fired : Boolean := False;

end Event;</lang> The event implementation: <lang ada>protected body Event is

  procedure Signal is
  begin
     Fired := True;
  end Signal;
  procedure Reset is
  begin
     Fired := False;
  end Reset;
  entry Wait when Fired is
  begin
     null;
  end Wait;

end Event;</lang> With the event defined above: <lang ada>with Ada.Text_IO; use Ada.Text_IO;

procedure Test_Events is

  -- Place the event implementation here
  X : Event;
  task A;
  task body A is
  begin
     Put_Line ("A is waiting for X");
     X.Wait;
     Put_Line ("A received X");
  end A;

begin

  delay 1.0;
  Put_Line ("Signal X");
  X.Signal;

end Test_Events;</lang> Sample output:

A is waiting for X
Signal X
A received X

AutoHotkey

<lang AutoHotkey>SetTimer, internal, 1000 Return

internal:  ; fire on a timer

 TrayTip, internal, internal event!`npress F2 for external event
 SetTimer, internal, off

Return

F2::  ; external event: fire on F2 key press

 TrayTip, external, f2 key pressed

Return</lang>

BBC BASIC

API

This uses a Windows event object: <lang bbcbasic> INSTALL @lib$+"TIMERLIB"

     WAIT_TIMEOUT = 258
     
     SYS "CreateEvent", 0, 1, 0, 0 TO hEvent%
     
     timerID% = FN_ontimer(1000, PROCelapsed, 0)
     
     PRINT "Waiting for event..."
     REPEAT
       SYS "WaitForSingleObject", hEvent%, 1 TO res%
     UNTIL res% <> WAIT_TIMEOUT
     PRINT "Event signalled"
     END
     
     DEF PROCelapsed
     SYS "SetEvent", hEvent%
     ENDPROC</lang>

Native

This uses a simple variable as a semaphore: <lang bbcbasic> INSTALL @lib$+"TIMERLIB"

     Event% = FALSE
     
     timerID% = FN_ontimer(1000, PROCelapsed, 0)
     
     PRINT "Waiting for event..."
     REPEAT
       WAIT 0
     UNTIL Event%
     PRINT "Event signalled"
     END
     
     DEF PROCelapsed
     Event% = TRUE
     ENDPROC</lang>

C

Using pipe to communicate to forked child. Since child will be blocking trying to read the other end of the pipe, this can be used for synchronization. <lang c>#include <stdio.h>

  1. include <unistd.h>

int main() { int p[2]; pipe(p); if (fork()) { close(p[0]); sleep(1); write(p[1], p, 1); wait(0); } else { close(p[1]); read(p[0], p + 1, 1); puts("received signal from pipe"); } return 0; }</lang>

C#

<lang csharp>using System; using System.Timers;

class Program {

   static void Main()
   {
       var timer = new Timer(1000);
       timer.Elapsed += new ElapsedEventHandler(OnElapsed);
       Console.WriteLine(DateTime.Now);
       timer.Start();
       Console.ReadLine();
   }
   static void OnElapsed(object sender, ElapsedEventArgs eventArgs)
   {
       Console.WriteLine(eventArgs.SignalTime);
       ((Timer)sender).Stop();
   }

}</lang> Sample output:

10-11-2010 18:35:11
10-11-2010 18:35:12

Delphi

<lang Delphi>program Events;

{$APPTYPE CONSOLE}

uses

 SysUtils, Classes, Windows;

type

 TWaitThread = class(TThread)
 private
   FEvent: THandle;
 public
   procedure Sync;
   procedure Execute; override;
   constructor Create(const aEvent: THandle); reintroduce;
 end;

{ TWaitThread }

constructor TWaitThread.Create(const aEvent: THandle); begin

 inherited Create(False);
 FEvent := aEvent;

end;

procedure TWaitThread.Execute; var

 res: Cardinal;

begin

 res := WaitForSingleObject(FEvent, INFINITE);
 if res = 0 then
   Synchronize(Sync);

end;

procedure TWaitThread.Sync; begin

 Writeln(DateTimeToStr(Now));

end;

var

 event: THandle;

begin

 Writeln(DateTimeToStr(Now));
 event := CreateEvent(nil, False, False, 'Event');
 with TWaitThread.Create(event) do
 try
   Sleep(1000);
   SetEvent(event)
 finally
   Free;
 end;
 Readln;

end.</lang> Sample output:

09.08.2011 0:27:43
09.08.2011 0:27:44

E

<lang e>def makeEvent() {

   def [var fired, var firer] := Ref.promise()
   
   def event {
       to signal() {
           firer.resolveRace(null) # all current and future wait()s will resolve
       }
       to reset() {
           if (firer.isDone()) { # ignore multiple resets. If we didn't, then
                                 # reset() wait() reset() signal() would never
                                 # resolve that wait().
               # create all fresh state
               def [p, r] := Ref.promise()
               fired := p
               firer := r
           }
       }
       to wait() {
           return fired
       }
   }
   
   return event

}</lang> The event object has this behavior: the return value of .wait() will be resolved after the time of the earliest .signal() for which there is no intervening .reset(). <lang e>def e := makeEvent()

{

   when (e.wait()) -> {
       println("[2] Received event.")
   }
   println("[2] Waiting for event...")

}

{

   timer.whenPast(timer.now() + 1000, def _() {
       println("[1] Signaling event.")
       e.signal()
   })
   println("[1] Waiting 1 second...")

}</lang>

Erlang

Events can be implemented by using the selective receive expression and erlang's built in message passing. Here task waits for the message 'go' before it will continue. <lang erlang> -module(events). -compile(export_all).

log(Msg) ->

   {H,M,S} = erlang:time(),
   io:fwrite("~2.B:~2.B:~2.B => ~s~n",[H,M,S,Msg]).

task() ->

   log("Task start"),
   receive
       go -> ok
   end,
   log("Task resumed").

main() ->

   log("Program start"),
   P = spawn(?MODULE,task,[]),
   log("Program sleeping"),
   timer:sleep(1000),
   log("Program signalling event"),
   P ! go,
   timer:sleep(100).

</lang> Output: <lang erlang> 66> events:main().

0: 0:57 => Program start
0: 0:57 => Program sleeping
0: 0:57 => Task start
0: 0:58 => Program signalling event
0: 0:58 => Task resumed

ok </lang>

F#

Translation of: C#

<lang fsharp>open System open System.Timers

let onElapsed (sender : obj) (eventArgs : ElapsedEventArgs) =

   printfn "%A" eventArgs.SignalTime
   (sender :?> Timer).Stop()

[<EntryPoint>] let main argv =

   let timer = new Timer(1000.)
   timer.Elapsed.AddHandler(new ElapsedEventHandler(onElapsed))
   printfn "%A" DateTime.Now
   timer.Start()
   ignore <| Console.ReadLine()
   0</lang>

Go

A Go channel can represent an manual-reset event, as described by the task. The two states of signaled and reset correspond to the presence or absence of a value on the channel. The program signals by sending a value on the channel. The event is reset when the waiting task explicitly executes the channel receive operation, <-event. <lang go>package main

import (

   "log"
   "os"
   "time"

)

func main() {

   l := log.New(os.Stdout, "", log.Ltime | log.Lmicroseconds)
   l.Println("program start")
   event := make(chan int)
   go func() {
       l.Println("task start")
       <-event
       l.Println("event reset by task")
   }()
   l.Println("program sleeping")
   time.Sleep(1 * time.Second)
   l.Println("program signaling event")
   event <- 0
   time.Sleep(100 * time.Millisecond)

}</lang>

Output:
01:27:21.862000 program start
01:27:21.862245 program sleeping
01:27:21.867269 task start
01:27:22.868294 program signaling event
01:27:22.868346 event reset by task

Haskell

<lang haskell>import Control.Concurrent (threadDelay, forkIO) import Control.Concurrent.SampleVar

-- An Event is defined as a SampleVar with no data. -- http://haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-SampleVar.html newtype Event = Event (SampleVar ())

newEvent = fmap Event (newEmptySampleVar) signalEvent (Event sv) = writeSampleVar sv () resetEvent (Event sv) = emptySampleVar sv waitEvent (Event sv) = readSampleVar sv</lang> <lang haskell>main = do e <- newEvent

         forkIO (waitTask e)
         putStrLn "[1] Waiting 1 second..."
         threadDelay 1000000 {- µs -}
         putStrLn "[1] Signaling event."
         signalEvent e
         threadDelay 1000000 {- µs -}    -- defer program exit for reception

waitTask e = do putStrLn "[2] Waiting for event..."

               waitEvent e
               putStrLn "[2] Received event."</lang>

Note: Because there is no serialization of the text output, there is a chance that it will appear interleaved.

Icon and Unicon

The following only works in Unicon. The example illustrates the multiple tasks can receive the same event: <lang unicon>record Event(cond, value)

procedure main()

   event := Event(condvar())
   t1 := thread {
       write("Task one waiting for event....")
       critical event.cond: while /(event.value) do wait(event.cond)
       write("Task one received event.")
       }
   t2 := thread {
       write("Task two waiting for event....")
       critical event.cond: while /(event.value) do wait(event.cond)
       write("Task two received event.")
       }
   delay(1000)                   # Let main thread post the event.
   event.value := "yes"
   write("Signalling event.")
   signal(event.cond,0)
   every wait(t1|t2)

end</lang>

Sample run:

->event
Task two waiting for event....
Task one waiting for event....
Signalling event.
Task two received event.
Task one received event.
->

JavaScript

An example using the YUI library: <lang javascript>YUI().use('event-custom', function(Y) {

   // add a custom event:
   Y.on('my:event', function () {
       alert("Event fired");
   });
   // fire the event after one second:
   setTimeout(function () {
       Y.fire('my:event');
   }, 1000);

});</lang> An example simulating DOM events: <lang javascript>YUI().use('node-event-simulate', function(Y) {

   // add a click event handler to a DOM node with id "button":
   Y.one("#button").on("click", function (e) {
       alert("Button clicked");
   });
   // simulate the click after one second:
   setTimeout(function () {
       Y.one("#button").simulate("click");
   }, 1000);

});</lang>

Mathematica

Mathematica supports events from timers (via Pause[]), task schedule descriptors. This will print a message after 4 seconds, then terminate the program. <lang Mathematica>Print["Will exit in 4 seconds"]; Pause[4]; Quit[] ->Will exit in 4 seconds</lang>

Nim

Translation of: C

<lang nim>import posix

var p: array[2, cint] discard pipe p if fork() > 0:

 discard close p[0]
 discard sleep 1
 discard p[1].write(addr p[0], 1)
 var x: cint = 0
 discard wait x

else:

 discard close p[1]
 discard p[0].read(addr p[1], 1)
 echo "received signal from pipe"</lang>


Oforth

An event is often implemented with a control channel. A task is waiting for an object on the channel. When the event occurs, another task sends an object on this channel.

<lang Oforth>func: anEvent { | ch |

  Channel new ->ch
  #[ ch receive "Ok, event is signaled !" println ] &
  System sleep(1000) 
  ch send($myEvent)

}</lang>

An emitter is a general implementation for handling events : an emitter waits for events emitted and launches listeners that are waiting for those events. <lang Oforth>func: anEvent2 { | e i |

  Emitter new(null) ->e
  e onEvent($myEvent, #[ "Ok, event is signaled !" println ])
  10 loop: i [ System sleep(1000) e emit($myEvent) ]
  e close

}</lang>

Oz

Translation of: Haskell

Events can be implemented as mutable references to dataflow variables: <lang oz>declare

 fun {NewEvent}
    {NewCell _}
 end
 proc {SignalEvent Event}
    @Event = unit
 end
 proc {ResetEvent Event}
    Event := _
 end
 proc {WaitEvent Event}
    {Wait @Event}
 end
 E = {NewEvent}

in

 thread
    {System.showInfo "[2] Waiting for event..."}
    {WaitEvent E}
    {System.showInfo "[2] Received event."}
 end
 {System.showInfo "[1] Waiting 1 second..."}
 {Delay 1000}
 {System.showInfo "[1] Signaling event."}
 {SignalEvent E}</lang>

However, this code is quite unidiomatic. If we need to wait for an event just once (like in this example), we can simply use a dataflow variable, i.e. an event that cannot be reset: <lang oz>declare

 E 

in

 thread
    {System.showInfo "[2] Waiting for event..."}
    {Wait E}
    {System.showInfo "[2] Received event."}
 end
 {System.showInfo "[1] Waiting 1 second..."}
 {Delay 1000}
 {System.showInfo "[1] Signaling event."}
 E = unit</lang>

If we want to synchronize two threads repeatedly and exchange data, it is natural to use ports and streams. Streams are just lists with an unbound tail. A port is basically a pointer to the tail of a list, i.e. it keeps track of where the next event can be written to: <lang oz>declare

 MyPort 

in

 thread
    MyStream
 in
    {NewPort ?MyStream ?MyPort}
    {System.showInfo "[2] Waiting for event..."}
    for Event in MyStream do

{System.showInfo "[2] Received event."} {System.showInfo "[2] Waiting for event again..."}

    end
 end
 for do
    {System.showInfo "[1] Waiting 1 second..."}
    {Delay 1000}
    {System.showInfo "[1] Signaling event."}
    {Port.send MyPort unit}
 end</lang>

It is important to limit the scope of a stream as much as possible to ensure that the already read part of the stream is garbage-collected.

Perl

This is an example of using the AnyEvent module. The result is this: it prints "Hello world!" after one second, then after another second prints "Hi!" four times every quarter of a second and then immediately prints "Bye!" and quits: <lang Perl>use AnyEvent;

  1. a new condition with a callback:

my $quit = AnyEvent->condvar(

   cb => sub {
       warn "Bye!\n";
   }

);

  1. a new timer, starts after 2s and repeats every 0.25s:

my $counter = 1; my $hi = AnyEvent->timer(

   after => 2,
   interval => 0.25,
   cb => sub {
       warn "Hi!\n";
       # flag the condition as ready after 4 times:
       $quit->send if ++$counter > 4;
   }

);

  1. another timer, runs the callback once after 1s:

my $hello = AnyEvent->timer(

   after => 1,
   cb => sub {
       warn "Hello world!\n";
   }

);

  1. wait for the $quit condition to be ready:

$quit->recv();</lang> This is the same using AnyEvent simplified API: <lang Perl>use AnyEvent;

my $quit = AE::cv sub { warn "Bye!\n" };

my $counter = 1; my $hi = AE::timer 2, 0.25, sub {

   warn "Hi!\n";
   $quit->send if ++$counter > 4;

};

my $hello = AE::timer 1, 0, sub {

   warn "Hello world!\n";

};

$quit->recv;</lang>

Perl 6

Translation of: Go

<lang perl6>note now, " program start"; my $event = Channel.new;

my $todo = start {

   note now, " task start";
   $event.receive;
   note now, " event reset by task";

}

note now, " program sleeping"; sleep 1; note now, " program signaling event"; $event.send(0); await $todo;</lang>

Output:
Instant:1403880984.089974 program start
Instant:1403880984.095400 program sleeping
Instant:1403880984.095491 task start
Instant:1403880985.099381 program signaling event
Instant:1403880985.109395 event reset by task

See also Handle_a_signal#Perl_6 for an example of using Supplies to do reactive programming based on events (Unix signals in this case).

PicoLisp

PicoLisp supports events from timers (via 'task' and 'alarm'), file descriptors (also 'task') and various 'signals'. This will print a message after one second, then terminate the program after another four seconds: <lang PicoLisp>(alarm 1

  (prinl "Exit in 4 seconds")
  (alarm 4 (bye)) )</lang>

PureBasic

<lang Purebasic>OpenWindow (0, 10, 10, 150, 40, "Event Demo") ButtonGadget (1, 10, 10, 35, 20, "Quit")

Repeat

  Event = WaitWindowEvent()  
  
  If  Event = #PB_Event_Gadget And EventGadget() = 1
     End         
  EndIf
  

ForEver</lang>

Racket

Racket comes with events as part of its implementation; various types of events are used for different purposes: there are events that become ready when some input is available in a port, when a TCP connection is made, when a thread is dead, etc etc. Here we use a simple alarm event as requested, even though it's a odd to send the actual event result to the task (since it's a useless value):

<lang racket>

  1. lang racket

(define task (thread (lambda () (printf "Got: ~s\n" (thread-receive)))))

(thread-send task ; wait for it, then send it

            (sync (alarm-evt (+ 1000 (current-inexact-milliseconds)))))

(void (sync task)) ; wait for the task to be done before exiting </lang>

REXX

Although REXX can be event driven, most events would probably have to be actively checked to see if the event occurs.
Here is a time-driven example of events happening, based on specific timer ticks. <lang rexx>/*REXX program shows a method of handling events (this is time-driven). */ signal on halt /*allow the user to HALT the pgm.*/ parse arg timeEvent /*allow "event" to be specified. */ if timeEvent= then timeEvent=5 /*if not specified, use default. */

event?: do forever /*determine if an event occurred.*/

        theEvent=right(time(),1)      /*maybe it's an event, maybe not.*/
        if pos(theEvent,timeEvent)\==0  then  signal happening
        end   /*forever*/

say 'Control should never get here!' /*This is a logic no-no occurance*/ halt: say 'program halted.'; exit /*stick a fork in it, we're done.*/ /*───────────────────────────────────HAPPENING processing───────────────*/ happening: say 'an event occurred at' time()", the event is:" theEvent

 do  while theEvent==right(time(),1); /*process the event here.*/ nop;end

signal event? /*see if another event happened. */</lang> output when using the input of:   1 3 5 0 7 9

an event occurred at 16:13:29, the event is: 9
an event occurred at 16:13:30, the event is: 0
an event occurred at 16:13:31, the event is: 1
an event occurred at 16:13:33, the event is: 3
an event occurred at 16:13:35, the event is: 5
an event occurred at 16:13:37, the event is: 7
an event occurred at 16:13:39, the event is: 9
an event occurred at 16:13:40, the event is: 0
an event occurred at 16:13:41, the event is: 1
an event occurred at 16:13:43, the event is: 3
an event occurred at 16:13:45, the event is: 5
an event occurred at 16:13:47, the event is: 7
an event occurred at 16:13:49, the event is: 9
an event occurred at 16:13:50, the event is: 0
an event occurred at 16:13:51, the event is: 1
an event occurred at 16:13:53, the event is: 3
program halted.

Tcl

Tcl has been event-driven since 7.5, but only supported channel and timer events (plus variable traces, which can be used to create event-like entitites). With the addition of coroutines, it becomes much simpler to create general events:

Works with: Tcl version 8.6

<lang tcl># Simple task framework built from coroutines proc pause ms {

   after $ms [info coroutine];yield

} proc task {name script} {

   coroutine $name apply [list {} \
       "set ::tasks(\[info coro]) 1;$script;unset ::tasks(\[info coro])"]

} proc waitForTasksToFinish {} {

   global tasks
   while {[array size tasks]} {

vwait tasks

   }

}

  1. Make an Ada-like event class

oo::class create Event {

   variable waiting fired
   constructor {} {

set waiting {} set fired 0

   }
   method wait {} {

while {!$fired} { lappend waiting [info coroutine] yield }

   }
   method signal {} {

set wake $waiting set waiting {} set fired 1 foreach task $wake { $task }

   }
   method reset {} {

set fired 0

   }

}

  1. Execute the example

Event create X task A {

   puts "waiting for event"
   X wait
   puts "received event"

} task B {

   pause 1000
   puts "signalling X"
   X signal

} waitForTasksToFinish</lang> Output:

waiting for event
signalling X
received event

Of course, the classic way of writing this is much shorter, but intermingles the tasks: <lang tcl>after 1000 set X signalled puts "waiting for event" vwait X puts "received event"</lang>

zkl

zkl provides an Atomics library for things like this. Events are async, waiting for an event doesn't poll. <lang zkl>var event=Atomic.Bool(); // False

  // create thread waiting for event

fcn(event){event.wait(); println(vm," ping!")}.launch(event); Atomic.sleep(1); event.set(); println("done")</lang>

Output:
// snooze
done   // setting is fast, receiving maybe not so
VM#4 ping!
// and thread 4 exits

I ran this from the REPL so I didn't have to worry about the main thread exiting and nuking the child thread.