Skip to content

Commit

Permalink
Added README & source from the first edition
Browse files Browse the repository at this point in the history
  • Loading branch information
kat-co committed May 29, 2017
1 parent 6c09121 commit 079a907
Show file tree
Hide file tree
Showing 79 changed files with 3,584 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.org
@@ -0,0 +1,3 @@
This is the full sourcecode for the book, "Concurrency in Go" published by O'Reilly.

For errata and more information, please refer to the book's hub at [[http://katherine.cox-buday.com/concurrency-in-go]].
@@ -0,0 +1,59 @@
package main

import (
"bytes"
"fmt"
"sync"
"sync/atomic"
"time"
)

func main() {
cadence := sync.NewCond(&sync.Mutex{})
go func() {
for range time.Tick(1 * time.Millisecond) {
cadence.Broadcast()
}
}()

takeStep := func() {
cadence.L.Lock()
cadence.Wait()
cadence.L.Unlock()
}

tryDir := func(dirName string, dir *int32, out *bytes.Buffer) bool { // <1>
fmt.Fprintf(out, " %v", dirName)
atomic.AddInt32(dir, 1) // <2>
takeStep() // <3>
if atomic.LoadInt32(dir) == 1 {
fmt.Fprint(out, ". Success!")
return true
}
takeStep()
atomic.AddInt32(dir, -1) // <4>
return false
}

var left, right int32
tryLeft := func(out *bytes.Buffer) bool { return tryDir("left", &left, out) }
tryRight := func(out *bytes.Buffer) bool { return tryDir("right", &right, out) }
walk := func(walking *sync.WaitGroup, name string) {
var out bytes.Buffer
defer func() { fmt.Println(out.String()) }()
defer walking.Done()
fmt.Fprintf(&out, "%v is trying to scoot:", name)
for i := 0; i < 5; i++ { // <1>
if tryLeft(&out) || tryRight(&out) { // <2>
return
}
}
fmt.Fprintf(&out, "\n%v tosses her hands up in exasperation!", name)
}

var peopleInHallway sync.WaitGroup // <3>
peopleInHallway.Add(2)
go walk(&peopleInHallway, "Alice")
go walk(&peopleInHallway, "Barbara")
peopleInHallway.Wait()
}
@@ -0,0 +1,56 @@
package main

import (
"fmt"
"sync"
"time"
)

func main() {
var wg sync.WaitGroup
var sharedLock sync.Mutex
const runtime = 1 * time.Second

greedyWorker := func() {
defer wg.Done()

var count int
for begin := time.Now(); time.Since(begin) <= runtime; {
sharedLock.Lock()
time.Sleep(3 * time.Nanosecond)
sharedLock.Unlock()
count++
}

fmt.Printf("Greedy worker was able to execute %v work loops\n", count)
}

politeWorker := func() {
defer wg.Done()

var count int
for begin := time.Now(); time.Since(begin) <= runtime; {
sharedLock.Lock()
time.Sleep(1 * time.Nanosecond)
sharedLock.Unlock()

sharedLock.Lock()
time.Sleep(1 * time.Nanosecond)
sharedLock.Unlock()

sharedLock.Lock()
time.Sleep(1 * time.Nanosecond)
sharedLock.Unlock()

count++
}

fmt.Printf("Polite worker was able to execute %v work loops.\n", count)
}

wg.Add(2)
go greedyWorker()
go politeWorker()

wg.Wait()
}
@@ -0,0 +1,24 @@
package main

import (
"fmt"
"sync"
)

func main() {
var memoryAccess sync.Mutex // <1>
var value int
go func() {
memoryAccess.Lock() // <2>
value++
memoryAccess.Unlock() // <3>
}()

memoryAccess.Lock() // <4>
if value == 0 {
fmt.Printf("the value is %v.\n", value)
} else {
fmt.Printf("the value is %v.\n", value)
}
memoryAccess.Unlock() // <5>
}
@@ -0,0 +1,15 @@
package main

import (
"fmt"
)

func main() {
var data int
go func() { // <1>
data++
}()
if data == 0 {
fmt.Printf("the value is %v.\n", data)
}
}
@@ -0,0 +1,85 @@
package main

import (
"fmt"
"log"
"os"
"os/exec"
"runtime/debug"
)

type MyError struct {
Inner error
Message string
StackTrace string
Misc map[string]interface{}
}

func wrapError(err error, messagef string, msgArgs ...interface{}) MyError {
return MyError{
Inner: err, //<1>
Message: fmt.Sprintf(messagef, msgArgs...),
StackTrace: string(debug.Stack()), // <2>
Misc: make(map[string]interface{}), // <3>
}
}

func (err MyError) Error() string {
return err.Message
}

// "lowlevel" module

type LowLevelErr struct {
error
}

func isGloballyExec(path string) (bool, error) {
info, err := os.Stat(path)
if err != nil {
return false, LowLevelErr{(wrapError(err, err.Error()))} // <1>
}
return info.Mode().Perm()&0100 == 0100, nil
}

// "intermediate" module

type IntermediateErr struct {
error
}

func runJob(id string) error {
const jobBinPath = "/bad/job/binary"
isExecutable, err := isGloballyExec(jobBinPath)
if err != nil {
return IntermediateErr{wrapError(
err,
"cannot run job %q: requisite binaries not available",
id,
)} // <1>
} else if isExecutable == false {
return wrapError(nil, "cannot run job %q: requisite binaries are not executable", id)
}

return exec.Command(jobBinPath, "--id="+id).Run()
}

func handleError(key int, err error, message string) {
log.SetPrefix(fmt.Sprintf("[logID: %v]: ", key))
log.Printf("%#v", err)
fmt.Printf("[%v] %v", key, message)
}

func main() {
log.SetOutput(os.Stdout)
log.SetFlags(log.Ltime | log.LUTC)

err := runJob("1")
if err != nil {
msg := "There was an unexpected issue; please report this as a bug."
if _, ok := err.(IntermediateErr); ok {
msg = err.Error()
}
handleError(1, err, msg)
}
}
81 changes: 81 additions & 0 deletions concurrency-at-scale/error-propagation/fig-error-propagation.go
@@ -0,0 +1,81 @@
package main

import (
"fmt"
"log"
"os"
"os/exec"
"runtime/debug"
)

type MyError struct {
Inner error
Message string
StackTrace string
Misc map[string]interface{}
}

func wrapError(err error, messagef string, msgArgs ...interface{}) MyError {
return MyError{
Inner: err, //<1>
Message: fmt.Sprintf(messagef, msgArgs...),
StackTrace: string(debug.Stack()), // <2>
Misc: make(map[string]interface{}), // <3>
}
}

func (err MyError) Error() string {
return err.Message
}

// "lowlevel" module

type LowLevelErr struct {
error
}

func isGloballyExec(path string) (bool, error) {
info, err := os.Stat(path)
if err != nil {
return false, LowLevelErr{(wrapError(err, err.Error()))} // <1>
}
return info.Mode().Perm()&0100 == 0100, nil
}

// "intermediate" module

type IntermediateErr struct {
error
}

func runJob(id string) error {
const jobBinPath = "/bad/job/binary"
isExecutable, err := isGloballyExec(jobBinPath)
if err != nil {
return err // <1>
} else if isExecutable == false {
return wrapError(nil, "job binary is not executable")
}

return exec.Command(jobBinPath, "--id="+id).Run() // <1>
}

func handleError(key int, err error, message string) {
log.SetPrefix(fmt.Sprintf("[logID: %v]: ", key))
log.Printf("%#v", err) // <3>
fmt.Printf("[%v] %v", key, message)
}

func main() {
log.SetOutput(os.Stdout)
log.SetFlags(log.Ltime | log.LUTC)

err := runJob("1")
if err != nil {
msg := "There was an unexpected issue; please report this as a bug."
if _, ok := err.(IntermediateErr); ok { // <1>
msg = err.Error()
}
handleError(1, err, msg) // <2>
}
}

0 comments on commit 079a907

Please sign in to comment.