Ошибка при тестировании реализации семафора - PullRequest
0 голосов
/ 24 апреля 2020

Я практикую параллельное программирование и приступил к реализации нескольких шаблонов и структур в go. Я также добавил тесты, в которых я использую семафор в качестве мьютекса для увеличения общего счетчика. Очевидно, что с моей реализацией что-то не так, потому что после запуска тестового файла несколько раз тесты проходят, а другие не проходят. Я предполагаю, что каким-то образом несколько потоков проходят вызов Wait () без блокировки и имеют параллельный доступ к переменной counter, но я не могу понять, почему. Любая помощь приветствуется!

семафор. 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)}
}

семафор_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)
    }

}


1 Ответ

1 голос
/ 24 апреля 2020

В Wait, когда вы просыпаетесь и блокируетесь, нет гарантии, что условие все еще выполняется. После блокировки вы должны проверить условие еще раз:

   for s.count == s.capacity {
        s.Unlock()
        <-s.condition
        s.Lock()
    }

В Signal вы должны count--, прежде чем разбудить других.

...