forked from lance-e/concurrent_labs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsemaphore_test.go
134 lines (114 loc) · 3.02 KB
/
semaphore_test.go
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
package main
import (
"concurrent_labs/semaphore"
"fmt"
"sync"
"testing"
"time"
)
// Producer function
func producer(id int, buffer int, sem *semaphore.Semaphore, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
time.Sleep(time.Millisecond * 100) // Simulate work
sem.P() // Acquire a token before producing
buffer++
fmt.Printf("Producer %d producing \n", id)
}
}
// Consumer function
func consumer(id int, buffer int, sem *semaphore.Semaphore, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
time.Sleep(time.Millisecond * 150) // Simulate work
sem.V() // Release the token after consuming
buffer--
fmt.Printf("Consumer %d consuming \n", id)
}
}
// Test Producer-Consumer with Semaphore
func TestProducerConsumer(t *testing.T) {
const numProducers = 3
const numConsumers = 3
buffer := 0
sem := semaphore.NewSemaphore(3) // Limit to one producer/consumer at the same time
var wg sync.WaitGroup
// Start producers
for i := 1; i <= numProducers; i++ {
wg.Add(1)
go producer(i, buffer, sem, &wg)
}
// Start consumers
for i := 1; i <= numConsumers; i++ {
wg.Add(1)
go consumer(i, buffer, sem, &wg)
}
wg.Wait() // Wait for all producers and consumers to finish
// Check if the buffer has the correct number of items
if buffer != 0 {
t.Errorf("Buffer should be empty, but has %d items", buffer)
}
}
// Test semaphore functionality
func TestSemaphoreFunctionality(t *testing.T) {
sem := semaphore.NewSemaphore(2) // Allow 2 concurrent accesses
var wg sync.WaitGroup
completed := make([]bool, 5)
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
sem.P()
time.Sleep(100 * time.Millisecond)
completed[id] = true
sem.V()
}(i)
}
wg.Wait() // Wait for all goroutines to finish
// Check if all goroutines have completed
for i := 0; i < 5; i++ {
if !completed[i] {
t.Errorf("Goroutine %d did not complete", i)
}
}
}
// Test semaphore exceeding limit
func TestSemaphoreExceedLimit(t *testing.T) {
sem := semaphore.NewSemaphore(1) // Limit to one access at the same time
var wg sync.WaitGroup
accessCount := 0
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
sem.P()
accessCount++
time.Sleep(50 * time.Millisecond) // Simulate work
sem.V()
}()
}
wg.Wait() // Wait for all goroutines to finish
// Check that accessCount should not exceed the limit
if accessCount > 10 {
t.Error("Access count exceeded the expected limit")
}
}
// Test immediate release of semaphore
func TestSemaphoreImmediateRelease(t *testing.T) {
sem := semaphore.NewSemaphore(1) // Limit to one access at the same time
var wg sync.WaitGroup
var accessed bool
wg.Add(1)
go func() {
defer wg.Done()
sem.P()
accessed = true
sem.V()
}()
time.Sleep(100 * time.Millisecond) // Ensure goroutine has time to run
// The semaphore should be released almost immediately after acquisition
if !accessed {
t.Fatal("The semaphore was not accessed as expected")
}
wg.Wait()
}