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
|
package demotemutex
import (
"testing"
)
// TestDemotion checks that a lock can be correctly demoted.
func TestDemotion(t *testing.T) {
value := 0
var dm DemoteMutex
c := make(chan int)
// Lock the mutex and update the value.
dm.Lock()
value++ // should set value to 1.
// Spawn a thread that will lock the value and update it.
go func() {
dm.Lock()
value++ // should set value to 2.
c <- value
dm.Unlock()
}()
// Spawn a thread that will read the value and send it down the channel.
//
// Ideally there's a way to guarantee that this thread runs after the other
// goroutine, to guarantee that the writelock is trying to acquire the
// mutex before the call to 'dm.RLock' is made. I could not find a way to
// get that guarantee.
go func() {
dm.RLock()
c <- value
dm.RUnlock()
}()
// Demote the lock, which will allow all threads attempting to aquire a
// readlock access to the lock without permitting any threads blocking for
// access to a writelock access to the lock.
//
// The thread blocking for a readlock should be able to aquire the lock and
// send the value '1' down the channel. It should not be blocked by the
// thread waiting for a writelock.
dm.Demote()
v := <-c
if v != 1 {
t.Fatal("demoting lock failed - value is unexpected")
}
// Allow threads blocking for a writelock access to the lock.
dm.DemotedUnlock()
// Pull a second value out of 'c' - it should be the value provided from
// the thread that writelocks and then increments to 2.
v = <-c
if v != 2 {
t.Fatal("value was not incremented to 2")
}
}
|