From f0ce635affce74ecee2dab8886f41324f21d4168 Mon Sep 17 00:00:00 2001 From: Drew Bednar Date: Mon, 14 Oct 2024 11:30:28 -0400 Subject: [PATCH] Finished sync --- learn_go_with_tests/my_sync/my_sync.go | 10 +++++++++ learn_go_with_tests/my_sync/my_sync_test.go | 25 ++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/learn_go_with_tests/my_sync/my_sync.go b/learn_go_with_tests/my_sync/my_sync.go index d56aca6..97f0e9d 100644 --- a/learn_go_with_tests/my_sync/my_sync.go +++ b/learn_go_with_tests/my_sync/my_sync.go @@ -1,10 +1,20 @@ package my_sync +import "sync" + type Counter struct { + // mutual exclusion lock. Zero value is an unlocked Mutex + + // If we embedded the type it would be c.Lock() but that also makes all other + // Mutex functions part of the public interface, which we don't want. + // sync.Mutex + mu sync.Mutex count int } func (c *Counter) Inc() { + c.mu.Lock() + defer c.mu.Unlock() c.count++ } diff --git a/learn_go_with_tests/my_sync/my_sync_test.go b/learn_go_with_tests/my_sync/my_sync_test.go index f544c74..acfbd99 100644 --- a/learn_go_with_tests/my_sync/my_sync_test.go +++ b/learn_go_with_tests/my_sync/my_sync_test.go @@ -1,11 +1,29 @@ package my_sync +// READ https://go.dev/wiki/MutexOrChannel. The gist is that go prefers to share data by +// communicating, not by sharing. This mean stylistically you will see a lot more chan than Mutex + +// Channels are good for +// passing ownership of data, +// distributing units of work, +// communicating async results + +// Mutexes are good for caches, state. + import ( "sync" "testing" ) -func assertCount(t testing.TB, got Counter, want int) { +// go vet +// # my_sync +// # [my_sync] +// ./my_sync_test.go:8:36: assertCount passes lock by value: my_sync.Counter contains sync.Mutex +// ./my_sync_test.go:22:18: call of assertCount copies lock value: my_sync.Counter contains sync.Mutex +// ./my_sync_test.go:42:18: call of assertCount copies lock value: my_sync.Counter contains sync.Mutex +// We don't want to copy a mutex. So this should be changed to take a pointer to a counter + +func assertCount(t testing.TB, got *Counter, want int) { t.Helper() if got.Value() != want { t.Errorf("got %d, want %d", got.Value(), want) @@ -14,12 +32,13 @@ func assertCount(t testing.TB, got Counter, want int) { func TestCounter(t *testing.T) { t.Run("Incrementing the counter 3 times leaves it at 3", func(t *testing.T) { + // We could also implemented a `func NewCounter() *Counter {}` if we wanted to. counter := Counter{} counter.Inc() counter.Inc() counter.Inc() - assertCount(t, counter, 3) + assertCount(t, &counter, 3) }) @@ -39,6 +58,6 @@ func TestCounter(t *testing.T) { // blocking call to wait for all goroutines wg.Wait() - assertCount(t, counter, wantedCount) + assertCount(t, &counter, wantedCount) }) }