-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsyncMutex2.go
More file actions
150 lines (136 loc) · 3.75 KB
/
Copy pathsyncMutex2.go
File metadata and controls
150 lines (136 loc) · 3.75 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package main
import (
"bytes"
"errors"
"fmt"
"io"
"log"
"sync"
"time"
)
// singleHandler 代表单次处理函数的类型。
type singleHandler func() (data string, n int, err error)
// handlerConfig 代表处理流程配置的类型。
type handlerConfig struct {
handler singleHandler // 单次处理函数。
goNum int // 需要启用的goroutine的数量。
number int // 单个goroutine中的处理次数。
interval time.Duration // 单个goroutine中的处理间隔时间。
counter int // 数据量计数器,以字节为单位。
counterMu sync.Mutex // 数据量计数器专用的互斥锁。
}
// count 会增加计数器的值,并会返回增加后的计数。
func (hc *handlerConfig) count(increment int) int {
hc.counterMu.Lock()
defer hc.counterMu.Unlock()
hc.counter += increment
return hc.counter
}
func main() {
// mu 代表以下流程要使用的互斥锁。
// 在下面的函数中直接使用即可,不要传递。
var mu sync.Mutex
// genWriter 代表的是用于生成写入函数的函数。
genWriter := func(writer io.Writer) singleHandler {
return func() (data string, n int, err error) {
// 准备数据。
data = fmt.Sprintf("%s\t",
time.Now().Format(time.StampNano))
// 写入数据。
mu.Lock()
defer mu.Unlock()
n, err = writer.Write([]byte(data))
return
}
}
// genReader 代表的是用于生成读取函数的函数。
genReader := func(reader io.Reader) singleHandler {
return func() (data string, n int, err error) {
buffer, ok := reader.(*bytes.Buffer)
if !ok {
err = errors.New("unsupported reader")
return
}
// 读取数据。
mu.Lock()
defer mu.Unlock()
data, err = buffer.ReadString('\t')
n = len(data)
return
}
}
// buffer 代表缓冲区。
var buffer bytes.Buffer
// 数据写入配置。
writingConfig := handlerConfig{
handler: genWriter(&buffer),
goNum: 5,
number: 4,
interval: time.Millisecond * 100,
}
// 数据读取配置。
readingConfig := handlerConfig{
handler: genReader(&buffer),
goNum: 10,
number: 2,
interval: time.Millisecond * 100,
}
// sign 代表信号的通道。
sign := make(chan struct{}, writingConfig.goNum+readingConfig.goNum)
// 启用多个goroutine对缓冲区进行多次数据写入。
for i := 1; i <= writingConfig.goNum; i++ {
go func(i int) {
defer func() {
sign <- struct{}{}
}()
for j := 1; j <= writingConfig.number; j++ {
time.Sleep(writingConfig.interval)
data, n, err := writingConfig.handler()
if err != nil {
log.Printf("writer [%d-%d]: error: %s",
i, j, err)
continue
}
total := writingConfig.count(n)
log.Printf("writer [%d-%d]: %s (total: %d)",
i, j, data, total)
}
}(i)
}
// 启用多个goroutine对缓冲区进行多次数据读取。
for i := 1; i <= readingConfig.goNum; i++ {
go func(i int) {
defer func() {
sign <- struct{}{}
}()
for j := 1; j <= readingConfig.number; j++ {
time.Sleep(readingConfig.interval)
var data string
var n int
var err error
for {
data, n, err = readingConfig.handler()
if err == nil || err != io.EOF {
break
}
// 如果读比写快(读时会发生EOF错误),那就等一会儿再读。
time.Sleep(readingConfig.interval)
}
if err != nil {
log.Printf("reader [%d-%d]: error: %s",
i, j, err)
continue
}
total := readingConfig.count(n)
log.Printf("reader [%d-%d]: %s (total: %d)",
i, j, data, total)
}
}(i)
}
// signNumber 代表需要接收的信号的数量。
signNumber := writingConfig.goNum + readingConfig.goNum
// 等待上面启用的所有goroutine的运行全部结束。
for j := 0; j < signNumber; j++ {
<-sign
}
}