Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 72ef8da

Browse files
add more examples + add 1 more slide in the mutexes presentation
1 parent 155c2a7 commit 72ef8da

File tree

7 files changed

+102
-41
lines changed

7 files changed

+102
-41
lines changed

‎mutexes/README.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ the database consistency which otherwise is not possible for a non-serial schedu
112112
- [Mutual Exclusion - Wiki](https://en.wikipedia.org/wiki/Mutual_exclusion)
113113
- [Dining Philosophers Problem - Wiki](https://en.wikipedia.org/wiki/Dining_philosophers_problem)
114114
- [Test and Set - Wiki](https://en.wikipedia.org/wiki/Test-and-set)
115+
- [Monitor - Wiki](https://en.wikipedia.org/wiki/Monitor_(synchronization))
115116
- [Tuple Space - Wiki](https://en.wikipedia.org/wiki/Tuple_space)
116117
- [Message Passing - Wiki](https://en.wikipedia.org/wiki/Message_passing)
117118
- [Semaphore - Wiki](https://en.wikipedia.org/wiki/Semaphore_(programming))
@@ -125,6 +126,12 @@ the database consistency which otherwise is not possible for a non-serial schedu
125126
- [Transaction Processing - Wiki](https://en.wikipedia.org/wiki/Transaction_processing)
126127
- [Pessimistic vs Optimistic Locking - StackOverflow](https://stackoverflow.com/questions/129329/optimistic-vs-pessimistic-locking)
127128
- [Pessimistic vs Optimistic Locking - StackOverflow Explanation](https://stackoverflow.com/a/58952004)
128-
- [Check Deadlock - Go Source Code](https://github.com/golang/go/blob/35ea62468bf7e3a79011c3ad713e847daa9a45a2/src/runtime/proc.go#L4159-L4233)
129+
- [Check Deadlock - Go Source Code](https://github.com/golang/go/blob/master/src/runtime/proc.go#L5122-L5221)
130+
- [Mutex.Lock() - Go Source Code](https://github.com/golang/go/blob/master/src/sync/mutex.go#L76)
131+
- [Mutex.lockSlow() - Go Source Code](https://github.com/golang/go/blob/master/src/sync/mutex.go#L108:17)
132+
- [RaceAcquire - Go Source Code](https://github.com/golang/go/blob/master/src/runtime/race.go#L37)
133+
- [raceacquire - Go Source Code](https://github.com/golang/go/blob/master/src/runtime/race.go#L515)
134+
- [racecall - Go Source Code](https://github.com/golang/go/blob/master/src/runtime/race.go#L348)
135+
- [racecall - GOASM Source Code](https://github.com/golang/go/blob/master/src/runtime/race_amd64.s#L384)
129136

130137
[Home](https://github.com/golang-basics/concurrency)
Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,71 @@
11
package main
22

33
import (
4+
"fmt"
45
"sync"
6+
"time"
57
)
68

7-
var mu sync.Mutex
8-
var c int
9-
10-
func task1() {}
11-
func task2() {}
12-
func task3() {}
13-
func inc() { c++ }
14-
159
func main() {
10+
var mu sync.Mutex
1611
var wg sync.WaitGroup
1712
wg.Add(2)
13+
1814
go func() {
1915
defer wg.Done()
20-
work1()
16+
now := time.Now()
17+
// work: ~6s | acquire after: ~6s
18+
// work1(&mu)
19+
// work: ~6s | acquire after: ~1s
20+
work2(&mu)
21+
fmt.Println("work is done after:", time.Since(now))
2122
}()
23+
24+
// simulate order of go routines
25+
time.Sleep(100 * time.Nanosecond)
26+
27+
// other go routine that needs the same mutex
2228
go func() {
2329
defer wg.Done()
24-
work2()
30+
now := time.Now()
31+
mu.Lock()
32+
fmt.Println("acquired lock after:", time.Since(now))
33+
mu.Unlock()
2534
}()
35+
2636
wg.Wait()
2737
}
2838

2939
// bad practice
30-
func work1() {
40+
func work1(mu*sync.Mutex) {
3141
mu.Lock()
3242
defer mu.Unlock()
3343
task1()
34-
inc()
35-
task2() // I/O
44+
task2()
3645
task3()
3746
}
3847

3948
// good practice
40-
func work2() {
41-
task1()
49+
func work2(mu *sync.Mutex) {
50+
// let's say only task 1 works with the CRITICAL SECTION
51+
// every other task is just part of the work
4252
func() {
4353
mu.Lock()
4454
defer mu.Unlock()
45-
inc()
55+
task1()
4656
}()
47-
task2()// I/O
57+
task2()
4858
task3()
4959
}
60+
61+
func task1() {
62+
time.Sleep(1 * time.Second)
63+
}
64+
65+
func task2() {
66+
time.Sleep(2 * time.Second)
67+
}
68+
69+
func task3() {
70+
time.Sleep(3 * time.Second)
71+
}

‎mutexes/mutex-implementation/mutex.c‎ renamed to ‎mutexes/mutex-implementation/main.c‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ void * pingpong(void * p) {
3333
} // for
3434
} // pingpong
3535

36-
// gcc mutex.c -o exec
36+
// gcc main.c -o exec
3737
// ./exec
3838
int main() {
3939
setvbuf(stdout, NULL, _IONBF, 0);
40-
pthread_t ping;
41-
pthread_t pong;
42-
pthread_create(&ping, NULL, pingpong, PING);
43-
pthread_create(&pong, NULL, pingpong, PONG);
40+
pthread_t ping_thread;
41+
pthread_t pong_thread;
42+
pthread_create(&ping_thread, NULL, pingpong, PING);
43+
pthread_create(&pong_thread, NULL, pingpong, PONG);
4444
for(;;);
4545
return 0;
4646
}

‎mutexes/mutex-implementation/main.go‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@ func main() {
1515
var wg sync.WaitGroup
1616

1717
// if we increase the number of go routines
18-
// this will quickly start to fail
19-
// due to go routines status being awake
20-
wg.Add(100)
21-
for i := 0; i < 100; i++ {
22-
go func(i int) {
18+
// this could quickly be detected as a race condition
19+
// due to too many go routines' status being awake
20+
// Also there's no way we can control the go routines queue
21+
// or have access to the runtime internals
22+
wg.Add(1000)
23+
for i := 0; i < 1000; i++ {
24+
go func() {
2325
defer wg.Done()
2426
mu.Lock()
25-
count=i
27+
count++
2628
mu.Unlock()
27-
}(i)
29+
}()
2830
}
2931
wg.Wait()
3032

@@ -40,7 +42,6 @@ func (mu *mutex) Lock() {
4042
return
4143
}
4244
for {
43-
// continue
4445
atomic.AddInt32(&mu.state, 1)
4546
s := atomic.LoadInt32(&mu.state)
4647
if s > 1 {
@@ -53,7 +54,7 @@ func (mu *mutex) Lock() {
5354
}
5455

5556
func (mu *mutex) Unlock() {
56-
if atomic.CompareAndSwapInt32(&mu.state, 1, 0) {
57+
for atomic.CompareAndSwapInt32(&mu.state, 1, 0) {
5758
return
5859
}
5960
panic("unlock of unlocked mutex")

‎mutexes/semaphore/main.go‎

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,44 @@
11
package main
22

3+
import (
4+
"fmt"
5+
"sync"
6+
"sync/atomic"
7+
)
8+
9+
var lock int32
10+
11+
// try running this with the -race flag
12+
// go run -race main.go
313
func main() {
4-
// implement semaphore using atomics
5-
// implement reentrant lock
6-
//while (test_and_set(&lock) == 1);
7-
//critical section // only one process can be in this section at a time
8-
//lock = 0; // release lock when finished with the critical section
14+
var count int
15+
var wg sync.WaitGroup
16+
17+
// if we increase the number of go routines
18+
// this could quickly be detected as a race condition
19+
// due to too many go routines' status being awake
20+
// Also there's no way we can control the go routines queue
21+
// or have access to the runtime internals
22+
wg.Add(1000)
23+
for i := 0; i < 1000; i++ {
24+
go func() {
25+
defer wg.Done()
26+
acquire()
27+
count++
28+
release()
29+
}()
30+
}
31+
32+
wg.Wait()
33+
fmt.Println("count", count)
34+
}
35+
36+
func acquire() {
37+
for atomic.CompareAndSwapInt32(&lock, 0, 1) {
38+
}
39+
}
40+
41+
func release() {
42+
for atomic.CompareAndSwapInt32(&lock, 1, 0) {
43+
}
944
}

‎mutexes/spinlock/main.go‎

Lines changed: 0 additions & 4 deletions
This file was deleted.

‎presentations/7_mutexes/Mutexes.key‎

19.9 KB
Binary file not shown.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /