我正在练习并发编程,并且已经着手实现了几种模式和结构。我还添加了一些测试,在这些测试中,我将信号量用作互斥体以增加共享计数器。我的实现显然存在问题,因为在几次运行测试文件后,有些测试通过了,而另一些则失败了。我的猜测是,多个线程在不阻塞的情况下通过了Wait()调用,并且可以并发访问计数器变量,但是我不知道为什么。任何帮助表示赞赏!
semaphore.go
package semaphore
import (
"sync"
)
type Semaphore struct {
capacity int
count int
sync.Mutex
condition chan bool
}
func (s *Semaphore) Wait() {
s.Lock()
defer s.Unlock()
if s.count == s.capacity {
s.Unlock()
<-s.condition
s.Lock()
}
s.count++
}
func (s *Semaphore) Signal() {
s.Lock()
defer s.Unlock()
select {
case s.condition <- true:
default:
}
s.count--
}
func NewSemaphore(n int) *Semaphore {
return &Semaphore{count: 0, capacity: n, condition: make(chan bool)}
}
semaphore_test.go
package semaphore
import (
"sync"
"testing"
)
func TestMutexSemaphore(t *testing.T) {
s := NewSemaphore(1)
wg := sync.WaitGroup{}
sharedCounter := 0
iters := 25
n := 20
testfun := func(mutex *Semaphore) {
defer wg.Done()
for j := 0; j < iters; j++ {
s.Wait()
sharedCounter++
s.Signal()
}
}
wg.Add(n)
for i := 0; i < n; i++ {
go testfun(s)
}
wg.Wait()
if sharedCounter != iters*n {
t.Errorf("Bad counter value:%d expected %d", sharedCounter, n*iters)
}
}
在Wait
中,当您唤醒并锁定时,无法保证条件仍然成立。锁定后,应再次检查条件:
for s.count == s.capacity {
s.Unlock()
<-s.condition
s.Lock()
}
在Signal
中,您应该在唤醒其他人之前count--
。