Исходники и презентации

This commit is contained in:
2025-05-23 07:26:39 +03:00
parent aa948179d5
commit 02d8430a3a
514 changed files with 13773 additions and 0 deletions

View File

@ -0,0 +1,16 @@
package main
import "sync/atomic"
// Need to show solution
type Data struct {
count atomic.Int32
}
func (d *Data) Process() {
d.count.Add(1)
if d.count.CompareAndSwap(100, 0) {
// do something...
}
}

View File

@ -0,0 +1,33 @@
package main
import (
"sync"
"sync/atomic"
"testing"
)
// go test -bench=. perf_test.go
func BenchmarkMutexAdd(b *testing.B) {
var number int32
var mutex sync.Mutex
for i := 0; i < b.N; i++ {
mutex.Lock()
number++
mutex.Unlock()
}
}
func BenchmarkAtomicAdd(b *testing.B) {
var number atomic.Int32
for i := 0; i < b.N; i++ {
number.Add(1)
}
}
func BenchmarkAdd(b *testing.B) {
var number int32
for i := 0; i < b.N; i++ {
number++
}
}

View File

@ -0,0 +1,15 @@
package main
import (
"sync/atomic"
)
func IncrementAndGet(pointer *int32) int32 {
for {
currentValue := atomic.LoadInt32(pointer)
nextValue := currentValue + 1
if atomic.CompareAndSwapInt32(pointer, currentValue, nextValue) {
return nextValue
}
}
}

View File

@ -0,0 +1,34 @@
package main
import (
"fmt"
"sync"
"sync/atomic"
)
// Need to show solution
var data map[string]string
var initialized atomic.Bool
func initialize() {
if !initialized.Load() {
initialized.Store(true)
data = make(map[string]string)
fmt.Println("initialized")
}
}
func main() {
wg := sync.WaitGroup{}
wg.Add(1000)
for i := 0; i < 1000; i++ {
go func() {
defer wg.Done()
initialize()
}()
}
wg.Wait()
}

View File

@ -0,0 +1,55 @@
package main
import (
"log"
"sync"
"time"
)
func subscribe(name string, data map[string]string, c *sync.Cond) {
c.L.Lock()
for len(data) == 0 {
c.Wait()
}
log.Printf("[%s] %s\n", name, data["key"])
c.L.Unlock()
}
func publish(name string, data map[string]string, c *sync.Cond) {
time.Sleep(time.Second)
c.L.Lock()
data["key"] = "value"
c.L.Unlock()
log.Printf("[%s] data publisher\n", name)
c.Broadcast()
}
func main() {
data := map[string]string{}
cond := sync.NewCond(&sync.Mutex{})
wg := sync.WaitGroup{}
wg.Add(3)
go func() {
defer wg.Done()
subscribe("subscriber_1", data, cond)
}()
go func() {
defer wg.Done()
subscribe("subscriber_2", data, cond)
}()
go func() {
defer wg.Done()
publish("publisher", data, cond)
}()
wg.Wait()
}

View File

@ -0,0 +1,20 @@
package main
import "sync"
func waitWithoutLock() {
cond := sync.NewCond(&sync.Mutex{})
cond.Wait()
}
func waitAfterSignal() {
cond := sync.NewCond(&sync.Mutex{})
cond.Signal()
cond.L.Lock()
cond.Wait()
cond.L.Unlock()
}
func main() {
}

View File

@ -0,0 +1,27 @@
package main
import (
"fmt"
"sync"
)
func main() {
mutex := sync.Mutex{}
wg := sync.WaitGroup{}
wg.Add(1000)
value := 0
for i := 0; i < 1000; i++ {
go func() {
defer wg.Done()
mutex.Lock()
value++
mutex.Unlock()
}()
}
wg.Wait()
fmt.Println(value)
}

View File

@ -0,0 +1,25 @@
package main
import (
"fmt"
"sync"
)
func main() {
text := ""
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
text = "hello world"
}()
go func() {
defer wg.Done()
fmt.Println(text)
}()
wg.Wait()
}

View File

@ -0,0 +1,42 @@
package main
import "sync"
// Need to show solution
var resource1 int
var resource2 int
func normalizeResources(lhs, rhs *sync.Mutex) {
lhs.Lock()
rhs.Lock()
// normalization
rhs.Unlock()
lhs.Unlock()
}
func main() {
var mutex1 sync.Mutex
var mutex2 sync.Mutex
wg := sync.WaitGroup{}
wg.Add(1000)
for i := 0; i < 500; i++ {
go func() {
defer wg.Done()
normalizeResources(&mutex1, &mutex2)
}()
}
for i := 0; i < 500; i++ {
go func() {
defer wg.Done()
normalizeResources(&mutex2, &mutex1)
}()
}
wg.Wait()
}

View File

@ -0,0 +1,55 @@
package main
import (
"log"
"sync"
"time"
)
// Need to show solution
var resource1 int
var resource2 int
func normalizeResources(lhs, rhs *sync.Mutex) {
lhs.Lock()
rhs.Lock()
// normalization
rhs.Unlock()
lhs.Unlock()
}
func main() {
var mutex1 sync.Mutex
var mutex2 sync.Mutex
wg := sync.WaitGroup{}
wg.Add(1000)
for i := 0; i < 500; i++ {
go func() {
defer wg.Done()
normalizeResources(&mutex1, &mutex2)
}()
}
for i := 0; i < 500; i++ {
go func() {
defer wg.Done()
normalizeResources(&mutex2, &mutex1)
}()
}
time.Sleep(time.Millisecond * 100)
go func() {
for {
time.Sleep(time.Second)
log.Println("tick")
}
}()
wg.Wait()
}

View File

@ -0,0 +1,21 @@
package main
import "sync"
// Need to show solution
var mutex sync.Mutex
func operation() {}
func doSomething() {
mutex.Lock()
operation()
mutex.Unlock()
// some long operation
mutex.Lock()
operation()
mutex.Unlock()
}

View File

@ -0,0 +1,42 @@
package main
import (
"log"
"sync"
)
var mutex sync.Mutex
func functionWithPanic() {
panic("error")
}
func handle1() {
defer func() {
if err := recover(); err != nil {
log.Println("recovered")
}
}()
mutex.Lock()
defer mutex.Unlock()
functionWithPanic()
}
func handle2() {
defer func() {
if err := recover(); err != nil {
log.Println("recovered")
}
}()
mutex.Lock()
functionWithPanic()
mutex.Unlock()
}
func main() {
handle1()
handle2()
}

View File

@ -0,0 +1,73 @@
package main
import (
"runtime"
"sync"
"sync/atomic"
"testing"
)
// go test -bench=. perf_test.go
type MutexCounter struct {
value int32
mutex sync.Mutex
}
func (c *MutexCounter) Increment(int) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.value++
}
func (c *MutexCounter) Get() int32 {
c.mutex.Lock()
defer c.mutex.Unlock()
return c.value
}
type AtomicCounter struct {
value atomic.Int32
}
func (c *AtomicCounter) Increment(int) {
c.value.Add(1)
}
func (c *AtomicCounter) Get() int32 {
return c.value.Load()
}
type ShardedAtomicCounter struct {
shards [10]AtomicCounter
}
func (c *ShardedAtomicCounter) Increment(idx int) {
c.shards[idx].value.Add(1)
}
func (c *ShardedAtomicCounter) Get() int32 {
var value int32
for idx := 0; idx < 10; idx++ {
value += c.shards[idx].Get()
}
return value
}
func BenchmarkAtomicCounter(b *testing.B) {
wg := sync.WaitGroup{}
wg.Add(runtime.NumCPU())
counter := MutexCounter{}
for i := 0; i < runtime.NumCPU(); i++ {
go func(idx int) {
defer wg.Done()
for j := 0; j < b.N; j++ {
counter.Increment(idx)
}
}(i)
}
wg.Wait()
}

View File

@ -0,0 +1,26 @@
package main
import "sync"
type Buffer struct {
mtx sync.Mutex
data []int
}
func NewBuffer() *Buffer {
return &Buffer{}
}
func (b *Buffer) Add(value int) {
b.mtx.Lock()
defer b.mtx.Unlock()
b.data = append(b.data, value)
}
func (b *Buffer) Data() []int {
b.mtx.Lock()
defer b.mtx.Unlock()
return b.data
}

View File

@ -0,0 +1,23 @@
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(1000)
value := 0
for i := 0; i < 1000; i++ {
go func() {
defer wg.Done()
value++
}()
}
wg.Wait()
fmt.Println(value)
}

View File

@ -0,0 +1,22 @@
package main
import "sync"
type Data struct {
sync.Mutex
values []int
}
func (d *Data) Add(value int) {
d.Lock()
defer d.Unlock()
d.values = append(d.values, value)
}
func main() {
data := Data{}
data.Add(100)
data.Unlock() // Possible problem!
}

View File

@ -0,0 +1,57 @@
package main
import (
"fmt"
"runtime"
"sync"
)
// Need to show solution
var mutex1 sync.Mutex
var mutex2 sync.Mutex
func goroutine1() {
mutex1.Lock()
runtime.Gosched()
for !mutex2.TryLock() {
// active waiting
}
mutex2.Unlock()
mutex1.Unlock()
fmt.Println("goroutine1 finished")
}
func goroutine2() {
mutex2.Lock()
runtime.Gosched()
for !mutex1.TryLock() {
// active waiting
}
mutex1.Unlock()
mutex2.Unlock()
fmt.Println("goroutine2 finished")
}
func main() {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
goroutine1()
}()
go func() {
defer wg.Done()
goroutine2()
}()
wg.Wait()
}

View File

@ -0,0 +1,34 @@
package main
import (
"fmt"
"sync"
)
// Need to show solution
var value int
func inc() {
mutex := sync.Mutex{}
mutex.Lock()
value++
mutex.Unlock()
}
func main() {
wg := sync.WaitGroup{}
wg.Add(1000)
for i := 0; i < 1000; i++ {
go func() {
defer wg.Done()
inc()
}()
}
wg.Wait()
fmt.Println(value)
}

View File

@ -0,0 +1,16 @@
package main
import (
"fmt"
"sync"
)
var mutex sync.Mutex
var cache map[string]string
func doSomething() {
mutex.Lock()
item := cache["key"]
fmt.Println(item)
mutex.Unlock()
}

View File

@ -0,0 +1,20 @@
package main
import "sync"
type Lockable[T any] struct {
sync.Mutex
Data T
}
func main() {
var l1 Lockable[int32]
l1.Lock()
l1.Data = 100
l1.Unlock()
var l2 Lockable[string]
l2.Lock()
l2.Data = "test"
l2.Unlock()
}

View File

@ -0,0 +1,21 @@
package main
import (
"fmt"
"sync"
)
var mutex sync.Mutex
var value string
func set(v string) {
mutex.Lock()
value = v
mutex.Unlock()
}
func print() {
mutex.Lock()
fmt.Println(value)
mutex.Unlock()
}

View File

@ -0,0 +1,35 @@
package main
import "sync"
func lockAnyTimes() {
mutex := sync.Mutex{}
mutex.Lock()
mutex.Lock()
}
func unlockWithoutLock() {
mutex := sync.Mutex{}
mutex.Unlock()
}
func unlockFromAnotherGoroutine() {
mutex := sync.Mutex{}
mutex.Lock()
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
mutex.Unlock()
}()
wg.Wait()
mutex.Lock()
mutex.Unlock()
}
func main() {
}

View File

@ -0,0 +1,34 @@
package main
import "sync"
// go run -race main.go
type Data struct {
X int
Y int
}
func main() {
var data Data
values := make([]int, 2)
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
data.X = 5
values[0] = 5
}()
go func() {
defer wg.Done()
data.Y = 10
values[1] = 10
}()
wg.Wait()
}

View File

@ -0,0 +1,31 @@
package main
import (
"log"
"sync"
)
// Need to show solution
func main() {
mutex := sync.Mutex{}
wg := sync.WaitGroup{}
wg.Add(1000)
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
value := 0
for j := 0; j < 10; j++ {
mutex.Lock()
value++
mutex.Unlock()
}
log.Println(value)
}()
}
wg.Wait()
}

View File

@ -0,0 +1,43 @@
package main
import (
"sync"
)
// Need to show solution
type Cache struct {
mutex sync.Mutex
data map[string]string
}
func NewCache() *Cache {
return &Cache{
data: make(map[string]string),
}
}
func (c *Cache) Set(key, value string) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.data[key] = value
}
func (c *Cache) Get(key string) string {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.Size() > 0 {
return c.data[key]
}
return ""
}
func (c *Cache) Size() int {
c.mutex.Lock()
defer c.mutex.Unlock()
return len(c.data)
}

View File

@ -0,0 +1,25 @@
package main
import "sync"
func withLock(mutex sync.Locker, action func()) {
if action == nil {
return
}
mutex.Lock()
defer mutex.Unlock()
action()
}
func main() {
mutex := sync.RWMutex{}
withLock(&mutex, func() {
// write lock
})
withLock(mutex.RLocker(), func() {
// read lock
})
}

View File

@ -0,0 +1,24 @@
package main
import "sync"
func RUnlockLockedMutex() {
m := sync.RWMutex{}
m.Lock()
m.RUnlock()
}
func UnlockRLockedMutex() {
m := sync.RWMutex{}
m.RLock()
m.Unlock()
}
func LockRLockedMutex() {
m := sync.RWMutex{}
m.Lock()
m.RLock()
}
func main() {
}

View File

@ -0,0 +1,28 @@
package main
import (
"sync"
"testing"
)
// go test -bench=. perf_test.go
func BenchmarkMutexAdd(b *testing.B) {
var number int32
var mutex sync.Mutex
for i := 0; i < b.N; i++ {
mutex.Lock()
number++
mutex.Unlock()
}
}
func BenchmarkRWMutexAdd(b *testing.B) {
var number int32
var mutex sync.RWMutex
for i := 0; i < b.N; i++ {
mutex.Lock()
number++
mutex.Unlock()
}
}

View File

@ -0,0 +1,23 @@
package main
import "sync"
type Counters struct {
mu sync.RWMutex
m map[string]int
}
func (c *Counters) Load(key string) (int, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
value, found := c.m[key]
return value, found
}
func (c *Counters) Store(key string, value int) {
c.mu.Lock()
defer c.mu.Unlock()
c.m[key] = value
}

View File

@ -0,0 +1,38 @@
package main
import (
"sync"
)
type Semaphore struct {
count int
max int
condition *sync.Cond
}
func NewSemaphore(limit int) *Semaphore {
mutex := &sync.Mutex{}
return &Semaphore{
max: limit,
condition: sync.NewCond(mutex),
}
}
func (s *Semaphore) Acquire() {
s.condition.L.Lock()
defer s.condition.L.Unlock()
for s.count >= s.max {
s.condition.Wait()
}
s.count++
}
func (s *Semaphore) Release() {
s.condition.L.Lock()
defer s.condition.L.Unlock()
s.count--
s.condition.Signal()
}

View File

@ -0,0 +1,59 @@
package main
import (
"fmt"
"sync"
"time"
)
// Starvation may be with processor, memory, file descriptors,
// connections with database and so on...
func main() {
var wg sync.WaitGroup
var mutex sync.Mutex
const runtime = 1 * time.Second
greedyWorker := func() {
defer wg.Done()
var count int
for begin := time.Now(); time.Since(begin) <= runtime; {
mutex.Lock()
time.Sleep(3 * time.Nanosecond)
mutex.Unlock()
count++
}
fmt.Printf("Greedy worker was able to execute %v work loops\n", count)
}
politeWorker := func() {
defer wg.Done()
var count int
for begin := time.Now(); time.Since(begin) <= runtime; {
mutex.Lock()
time.Sleep(1 * time.Nanosecond)
mutex.Unlock()
mutex.Lock()
time.Sleep(1 * time.Nanosecond)
mutex.Unlock()
mutex.Lock()
time.Sleep(1 * time.Nanosecond)
mutex.Unlock()
count++
}
fmt.Printf("Polite worker was able to execute %v work loops.\n", count)
}
wg.Add(2)
go greedyWorker()
go politeWorker()
wg.Wait()
}

View File

@ -0,0 +1,76 @@
package main
import (
"sync"
)
// Need to show solution
type Stack struct {
mutex sync.Mutex
data []string
}
func NewStack() Stack {
return Stack{}
}
func (b Stack) Push(value string) {
b.mutex.Lock()
defer b.mutex.Unlock()
b.data = append(b.data, value)
}
func (b Stack) Pop() {
if len(b.data) < 0 {
panic("pop: stack is empty")
}
b.mutex.Lock()
defer b.mutex.Unlock()
b.data = b.data[:len(b.data)-1]
}
func (b Stack) Top() string {
if len(b.data) < 0 {
panic("top: stack is empty")
}
b.mutex.Lock()
defer b.mutex.Unlock()
return b.data[len(b.data)-1]
}
var stack Stack
func producer() {
for i := 0; i < 1000; i++ {
stack.Push("message")
}
}
func consumer() {
for i := 0; i < 10; i++ {
_ = stack.Top()
stack.Pop()
}
}
func main() {
producer()
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer wg.Done()
consumer()
}()
}
wg.Wait()
}

View File

@ -0,0 +1,14 @@
package main
import "sync"
func done(wg sync.WaitGroup) {
wg.Done()
}
func main() {
wg := sync.WaitGroup{}
wg.Add(1)
done(wg)
wg.Wait()
}

View File

@ -0,0 +1,16 @@
package main
import "sync"
func makeNegativeCounter() {
wg := sync.WaitGroup{}
wg.Add(-10)
}
func waitZeroCounter() {
wg := sync.WaitGroup{}
wg.Wait()
}
func main() {
}

View File

@ -0,0 +1,13 @@
package main
import "log"
// Need to show solution
func main() {
for i := 0; i < 5; i++ {
go func() {
log.Println("test")
}()
}
}