Skip to content

Commit 8ce188f

Browse files
authored
Merge pull request #776 from devlights/add-sync-rwmutex-example
2 parents cdd23bb + 25966fc commit 8ce188f

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

examples/basic/syncs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@
1919
| use_oncevalues.go | syncs_use_oncevalues | Go 1.21 で追加された sync.OnceValues() のサンプルです |
2020
| use_pool.go | syncs_use_pool | sync.Poolのサンプルです |
2121
| mutex_trylock.go | syncs_mutex_trylock | Go 1.18 で追加された mutex.TryLock() についてのサンプルです。 |
22+
| use_rwmutex.go | syncs_use_rwmutex | sync.RWMutex のサンプルです。 |

examples/basic/syncs/examples.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func (r *register) Regist(m mapping.ExampleMapping) {
1919
m["syncs_atomic_compare_and_swap"] = CompareAndSwap
2020
m["syncs_use_channel"] = UseChannel
2121
m["syncs_use_mutex"] = UseMutex
22+
m["syncs_use_rwmutex"] = UseRWMutex
2223
m["syncs_use_cond_signal"] = UseCondSignal
2324
m["syncs_use_cond_broadcast"] = UseCondBroadcast
2425
m["syncs_use_map"] = UseMap
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package syncs
2+
3+
import (
4+
"context"
5+
"log"
6+
"sync"
7+
"time"
8+
)
9+
10+
// UseRWMutex は、sync.RWMutex のサンプルです。
11+
//
12+
// RWMutexは、読み取りと書き込みで別々にロックを取れるMutex。
13+
//
14+
// ドキュメントには以下のように記載されている。
15+
//
16+
// > A RWMutex is a reader/writer mutual exclusion lock. The lock can be held by an arbitrary number of readers or a single writer.
17+
// The zero value for a RWMutex is an unlocked mutex.
18+
//
19+
// > (RWMutexは、リーダ/ライタ相互排他ロックである。このロックは、任意の数のリー ダーまたは1人のライターが保持することができる。
20+
// RWMutexのゼロ値は、アンロックされたミューテックスである。)
21+
//
22+
// > If any goroutine calls Lock while the lock is already held by one or more readers,
23+
// concurrent calls to RLock will block until the writer has acquired (and released) the lock,
24+
// to ensure that the lock eventually becomes available to the writer.
25+
// Note that this prohibits recursive read-locking.
26+
//
27+
// > ロックがすでに1つ以上のリーダによって保持されている間に、いずれかのゴルーチンがLockを呼び出すと、
28+
// RLockの同時呼び出しは、ライタがロックを獲得(および解放)するまでブロックされ、ロックが最終的にライタが利用できるようになる。
29+
// これは再帰的な読み取りロックを禁止していることに注意してください。
30+
//
31+
// RLockが読み取り用、Lockが書き込み用となる。RLockは複数のゴルーチンが取れるが、Lockは排他ロックとなる。
32+
//
33+
// # REFERENCES
34+
// - https://pkg.go.dev/sync@go1.22.1#RWMutex
35+
func UseRWMutex() error {
36+
//
37+
// 3つのゴルーチンがあり、2つは値の読み取り(RLock)、1つは値の書き込み(Lock)を行う。
38+
//
39+
40+
log.SetFlags(log.Lmicroseconds)
41+
42+
var (
43+
v int64
44+
m sync.RWMutex
45+
read = func(ctx context.Context, prefix string, interval time.Duration) {
46+
for {
47+
select {
48+
case <-ctx.Done():
49+
return
50+
default:
51+
}
52+
53+
func() {
54+
m.RLock()
55+
defer m.RUnlock()
56+
57+
log.Printf("[%s] %v", prefix, v)
58+
59+
select {
60+
case <-ctx.Done():
61+
case <-time.After(interval):
62+
}
63+
}()
64+
}
65+
}
66+
write = func(ctx context.Context, prefix string, interval time.Duration) {
67+
for {
68+
// 1秒間、RLockできる猶予を与える
69+
select {
70+
case <-ctx.Done():
71+
return
72+
case <-time.After(1 * time.Second):
73+
}
74+
75+
// ここから interval の間は排他ロックとなる
76+
func() {
77+
m.Lock()
78+
defer m.Unlock()
79+
80+
old := v
81+
v++
82+
83+
log.Printf("[%s] %v --> %v", prefix, old, v)
84+
85+
select {
86+
case <-ctx.Done():
87+
case <-time.After(interval):
88+
}
89+
}()
90+
}
91+
}
92+
)
93+
94+
ctx, cxl := context.WithTimeout(context.Background(), 10*time.Second)
95+
defer cxl()
96+
97+
go read(ctx, "READ-1", 500*time.Millisecond)
98+
go read(ctx, "READ-2", 250*time.Millisecond)
99+
go write(ctx, "WRITE-1", 2*time.Second)
100+
101+
<-ctx.Done()
102+
log.Println("DONE")
103+
104+
return nil
105+
}

0 commit comments

Comments
 (0)