tour: add explanation of sync.Mutex

sync.Mutex is needed to solve the last exercise of the tour

Fixes golang/go#13110

Change-Id: I0b10f8c0fc0e3c656377b93bdbf40e38c5cb762b
Reviewed-by: Rob Pike <>
diff --git a/content/concurrency.article b/content/concurrency.article
index 8dd1308..9bb55c0 100644
--- a/content/concurrency.article
+++ b/content/concurrency.article
@@ -130,12 +130,37 @@
 .play concurrency/exercise-equivalent-binary-trees.go
+* sync.Mutex
+We've seen how channels are great for communication among goroutines.
+But what if we don't need communication? What if we just want to make sure only
+one goroutine can access a variable at a time to avoid conflicts?
+This concept is called _mutual_exclusion_, and the conventional name for the data structure that provides it is _mutex_.
+Go's standard library provides mutual exclusion with
+[[][`sync.Mutex`]] and its two methods:
+- `Lock`
+- `Unlock`
+We can define a block of code to be executed in mutual exclusion by surrounding it
+with a call to `Lock` and `Unlock` as shown on the `Inc` method.
+We can also use `defer` to ensure the mutex will be unlocked as in the `Value` method.
+ concurrency/mutex-counter.go
 * Exercise: Web Crawler
 In this exercise you'll use Go's concurrency features to parallelize a web crawler.
 Modify the `Crawl` function to fetch URLs in parallel without fetching the same URL twice.
+_Hint_: you can keep a cache of the URLs that have been fetched on a map, but maps alone are not
+safe for concurrent use!
 .play concurrency/exercise-web-crawler.go
 * Where to Go from here...
diff --git a/content/concurrency/mutex-counter.go b/content/concurrency/mutex-counter.go
new file mode 100644
index 0000000..ed727bd
--- /dev/null
+++ b/content/concurrency/mutex-counter.go
@@ -0,0 +1,41 @@
+// +build OMIT
+package main
+import (
+	"fmt"
+	"sync"
+	"time"
+// SafeCounter is safe to use concurrently.
+type SafeCounter struct {
+	v   map[string]int
+	mux sync.Mutex
+// Inc increments the counter for the given key.
+func (c *SafeCounter) Inc(key string) {
+	c.mux.Lock()
+	// Lock so only one goroutine at a time can access the map c.v.
+	c.v[key]++
+	c.mux.Unlock()
+// Value returns the current value of the counter for the given key.
+func (c *SafeCounter) Value(key string) int {
+	c.mux.Lock()
+	// Lock so only one goroutine at a time can access the map c.v.
+	defer c.mux.Unlock()
+	return c.v[key]
+func main() {
+	c := SafeCounter{v: make(map[string]int)}
+	for i := 0; i < 1000; i++ {
+		go c.Inc("somekey")
+	}
+	time.Sleep(time.Second)
+	fmt.Println(c.Value("somekey"))