diff options
-rw-r--r-- | exercises/concurrent/concurrent1/main_test.go | 45 | ||||
-rw-r--r-- | exercises/concurrent/concurrent2/main_test.go | 32 | ||||
-rw-r--r-- | golings/exercises/runner.go | 2 | ||||
-rw-r--r-- | info.toml | 26 |
4 files changed, 104 insertions, 1 deletions
diff --git a/exercises/concurrent/concurrent1/main_test.go b/exercises/concurrent/concurrent1/main_test.go new file mode 100644 index 0000000..3965113 --- /dev/null +++ b/exercises/concurrent/concurrent1/main_test.go @@ -0,0 +1,45 @@ +// concurrent1 +// Make the tests pass! + +// I AM NOT DONE +package main_test + +import ( + "bytes" + "fmt" + "sync" + "testing" +) + +func TestPrinter(t *testing.T) { + var buf bytes.Buffer + print(&buf) + + out := buf.String() + + for i := 0; i < 3; i++ { + want := fmt.Sprintf("Hello from goroutine %d!", i) + if !bytes.Contains([]byte(out), []byte(want)) { + t.Errorf("Output did not contain expected string. Wanted: %q, Got: %q", want, out) + } + } +} + +func print(buf *bytes.Buffer) { + var wg sync.WaitGroup + var mu sync.Mutex + + goroutines := 3 + + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + mu.Lock() + //fmt.Fprintf(buf, "Hello from goroutine %d!\n", i) + mu.Unlock() + }(i) + } + + wg.Wait() +} diff --git a/exercises/concurrent/concurrent2/main_test.go b/exercises/concurrent/concurrent2/main_test.go new file mode 100644 index 0000000..2233259 --- /dev/null +++ b/exercises/concurrent/concurrent2/main_test.go @@ -0,0 +1,32 @@ +// concurrent2 +// Make the tests pass! + +// I AM NOT DONE +package main_test + +import ( + "sync" + "testing" +) + +func TestCounter(t *testing.T) { + counter := updateCounter() + if counter != 100 { + t.Errorf("Counter should be 100, but got %d", counter) + } +} + +func updateCounter() int { + var counter int + var wg sync.WaitGroup + + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + defer wg.Done() + counter++ // Many goroutines trying to update the counter? We need some protection here! + }() + } + wg.Wait() + return counter +} diff --git a/golings/exercises/runner.go b/golings/exercises/runner.go index 17b5f61..e9bc202 100644 --- a/golings/exercises/runner.go +++ b/golings/exercises/runner.go @@ -29,7 +29,7 @@ func BuildArgs(e Exercise) []string { if e.Mode == "compile" { args = append(args, "run") } else { - args = append(args, "test", "-v") + args = append(args, "test", "-v", "-race") } args = append(args, fmt.Sprintf("./%s", e.Path)) @@ -316,3 +316,29 @@ In go, we can declare type constraints. It is the case of our Number interface. Don't forget the type signature. """ + +[[exercises]] +name = "concurrent1" +path = "exercises/concurrent/concurrent1/main_test.go" +mode = "test" +hint = """ +We have multiple printers (as the others, these ones don't work too). + +Our goal is to print something. But what is this? +""" + +[[exercises]] +name = "concurrent2" +path = "exercises/concurrent/concurrent2/main_test.go" +mode = "test" +hint = """ +Updating a variable from multiple goroutines can lead to a data race. +A data race is when the same variable is concurrently read and written by multiple goroutines without +any kind of protection. + +Imagine if a program is reading a variable while another one is writing. + +A counter is a good example. Your counter could be updated with a different value than expected. + +Read a little about mutexes: https://pkg.go.dev/sync#Mutex. +""" |