Skip to content

Commit 72ef8da

Browse files
committed
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.
19.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)