Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
145
Task/Rendezvous/Go/rendezvous.go
Normal file
145
Task/Rendezvous/Go/rendezvous.go
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var hdText = `Humpty Dumpty sat on a wall.
|
||||
Humpty Dumpty had a great fall.
|
||||
All the king's horses and all the king's men,
|
||||
Couldn't put Humpty together again.`
|
||||
|
||||
var mgText = `Old Mother Goose,
|
||||
When she wanted to wander,
|
||||
Would ride through the air,
|
||||
On a very fine gander.
|
||||
Jack's mother came in,
|
||||
And caught the goose soon,
|
||||
And mounting its back,
|
||||
Flew up to the moon.`
|
||||
|
||||
func main() {
|
||||
reservePrinter := startMonitor(newPrinter(5), nil)
|
||||
mainPrinter := startMonitor(newPrinter(5), reservePrinter)
|
||||
var busy sync.WaitGroup
|
||||
busy.Add(2)
|
||||
go writer(mainPrinter, "hd", hdText, &busy)
|
||||
go writer(mainPrinter, "mg", mgText, &busy)
|
||||
busy.Wait()
|
||||
}
|
||||
|
||||
// printer is a type representing an abstraction of a physical printer.
|
||||
// It is a type defintion for a function that takes a string to print
|
||||
// and returns an error value, (hopefully usually nil, meaning no error.)
|
||||
type printer func(string) error
|
||||
|
||||
// newPrinter is a constructor. The parameter is a quantity of ink. It
|
||||
// returns a printer object encapsulating the ink quantity.
|
||||
// Note that this is not creating the monitor, only the object serving as
|
||||
// a physical printer by writing to standard output.
|
||||
func newPrinter(ink int) printer {
|
||||
return func(line string) error {
|
||||
if ink == 0 {
|
||||
return eOutOfInk
|
||||
}
|
||||
for _, c := range line {
|
||||
fmt.Printf("%c", c)
|
||||
}
|
||||
fmt.Println()
|
||||
ink--
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var eOutOfInk = errors.New("out of ink")
|
||||
|
||||
// For the language task, rSync is a type used to approximate the Ada
|
||||
// rendezvous mechanism that includes the caller waiting for completion
|
||||
// of the callee. For this use case, we signal completion with an error
|
||||
// value as a response. Exceptions are not idiomatic in Go and there is
|
||||
// no attempt here to model the Ada exception mechanism. Instead, it is
|
||||
// idomatic in Go to return error values. Sending an error value on a
|
||||
// channel works well here to signal completion. Go unbuffered channels
|
||||
// provide synchronous rendezvous, but call and response takes two channels,
|
||||
// which are bundled together here in a struct. The channel types are chosen
|
||||
// to mirror the parameter and return types of "type printer" defined above.
|
||||
// The channel types here, string and error are both "reference types"
|
||||
// in Go terminology. That is, they are small things containing pointers
|
||||
// to the actual data. Sending one on a channel does not involve copying,
|
||||
// or much less marshalling string data.
|
||||
type rSync struct {
|
||||
call chan string
|
||||
response chan error
|
||||
}
|
||||
|
||||
// "rendezvous Print" requested by use case task.
|
||||
// For the language task though, it is implemented here as a method on
|
||||
// rSync that sends its argument on rSync.call and returns the result
|
||||
// received from rSync.response. Each channel operation is synchronous.
|
||||
// The two operations back to back approximate the Ada rendezvous.
|
||||
func (r *rSync) print(data string) error {
|
||||
r.call <- data // blocks until data is accepted on channel
|
||||
return <-r.response // blocks until response is received
|
||||
}
|
||||
|
||||
// monitor is run as a goroutine. It encapsulates the printer passed to it.
|
||||
// Print requests are received through the rSync object "entry," named entry
|
||||
// here to correspond to the Ada concept of an entry point.
|
||||
func monitor(hardPrint printer, entry, reserve *rSync) {
|
||||
for {
|
||||
// The monitor goroutine will block here waiting for a "call"
|
||||
// to its "entry point."
|
||||
data := <-entry.call
|
||||
// Assuming the call came from a goroutine calling rSync.print,
|
||||
// that goroutine is now blocked, waiting for this one to send
|
||||
// a response.
|
||||
|
||||
// attempt output
|
||||
switch err := hardPrint(data); {
|
||||
|
||||
// consider return value from attempt
|
||||
case err == nil:
|
||||
entry.response <- nil // no problems
|
||||
|
||||
case err == eOutOfInk && reserve != nil:
|
||||
// Requeue to "entry point" of reserve printer monitor.
|
||||
// Caller stays blocked, and now this goroutine blocks until
|
||||
// it gets a response from the reserve printer monitor.
|
||||
// It then transparently relays the response to the caller.
|
||||
entry.response <- reserve.print(data)
|
||||
|
||||
default:
|
||||
entry.response <- err // return failure
|
||||
}
|
||||
// The response is away. Loop, and so immediately block again.
|
||||
}
|
||||
}
|
||||
|
||||
// startMonitor can be seen as an rSync constructor. It also
|
||||
// of course, starts the monitor for which the rSync serves as entry point.
|
||||
// Further to the langauge task, note that the channels created here are
|
||||
// unbuffered. There is no buffer or message box to hold channel data.
|
||||
// A sender will block waiting for a receiver to accept data synchronously.
|
||||
func startMonitor(p printer, reservePrinter *rSync) *rSync {
|
||||
entry := &rSync{make(chan string), make(chan error)}
|
||||
go monitor(p, entry, reservePrinter)
|
||||
return entry
|
||||
}
|
||||
|
||||
// Two writer tasks are started as goroutines by main. They run concurrently
|
||||
// and compete for printers as resources. Note the call to "rendezvous Print"
|
||||
// as requested in the use case task and compare the syntax,
|
||||
// Here: printMonitor.print(line);
|
||||
// Ada solution: Main.Print ("string literal");
|
||||
func writer(printMonitor *rSync, id, text string, busy *sync.WaitGroup) {
|
||||
for _, line := range strings.Split(text, "\n") {
|
||||
if err := printMonitor.print(line); err != nil {
|
||||
fmt.Printf("**** writer task %q terminated: %v ****\n", id, err)
|
||||
break
|
||||
}
|
||||
}
|
||||
busy.Done()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue