forked from ardanlabs/gotraining
-
Notifications
You must be signed in to change notification settings - Fork 0
/
example5.go
104 lines (84 loc) · 2.38 KB
/
example5.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// All material is licensed under the Apache License Version 2.0, January 2004
// http://www.apache.org/licenses/LICENSE-2.0
// Sample program to show how to use a read/write mutex to define critical
// sections of code that needs synchronous access.
package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
var (
// data is a slice that will be shared.
data []string
// rwMutex is used to define a critical section of code.
rwMutex sync.RWMutex
// Number of reads occurring at ay given time.
readCount int64
)
// init is called prior to main.
func init() {
rand.Seed(time.Now().UnixNano())
}
func main() {
// wg is used to manage concurrency.
var wg sync.WaitGroup
wg.Add(1)
// Create the writer goroutine.
go func() {
writer()
wg.Done()
}()
// To keep the sample simple we are allowing the runtime to
// kill the reader goroutines. This is something we should
// control before allowing main to exit.
// Create seven reader goroutines.
for i := 1; i <= 7; i++ {
go reader(i)
}
// Wait for the write goroutine to finish.
wg.Wait()
fmt.Println("Program Complete")
}
// writer adds 10 new strings to the slice in random intervals.
func writer() {
for i := 1; i <= 10; i++ {
// Only allow one goroutine to read/write to the
// slice at a time.
rwMutex.Lock()
{
// Capture the current read count.
// Keep this safe though we can due without this call.
rc := atomic.LoadInt64(&readCount)
// Perform some work since we have a full lock.
fmt.Printf("****> : Performing Write : RCount[%d]\n", rc)
data = append(data, fmt.Sprintf("String: %d", i))
}
rwMutex.Unlock()
// Release the lock and allow any waiting goroutines
// to continue using the slice.
// Sleep a random amount of time.
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
}
}
// reader wakes up and iterates over the data slice.
func reader(id int) {
for {
// Any goroutine can read when no write
// operation is taking place.
rwMutex.RLock()
{
// Increment the read count value by 1.
rc := atomic.AddInt64(&readCount, 1)
// Perform some read work and display values.
time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
fmt.Printf("%d : Performing Read : Length[%d] RCount[%d]\n", id, len(data), rc)
// Decrement the read count value by 1.
atomic.AddInt64(&readCount, -1)
}
rwMutex.RUnlock()
// Release the read lock.
}
}