diff --git a/homeworks/13_sync_primitives/homework.go b/homeworks/13_sync_primitives/homework.go index 05c8b47..a13336f 100644 --- a/homeworks/13_sync_primitives/homework.go +++ b/homeworks/13_sync_primitives/homework.go @@ -22,7 +22,12 @@ func (m *RWMutex) Lock() { m.mutex.Lock() defer m.mutex.Unlock() - m.underLock() + m.writersWaiting++ + for m.writerActive || m.readerCount != 0 { + m.writerCond.Wait() + } + m.writerActive = true + m.writersWaiting-- } func (m *RWMutex) Unlock() { @@ -36,7 +41,10 @@ func (m *RWMutex) RLock() { m.mutex.Lock() defer m.mutex.Unlock() - m.underRLock() + for m.writerActive || m.writersWaiting > 0 { + m.writerCond.Wait() + } + m.readerCount++ } func (m *RWMutex) RUnlock() { @@ -49,41 +57,25 @@ func (m *RWMutex) RUnlock() { } func (m *RWMutex) TryLock() bool { - ok := m.mutex.TryLock() - if !ok { - return false - } + m.mutex.Lock() defer m.mutex.Unlock() - m.underLock() + if m.writerActive || m.readerCount > 0 { + return false + } + m.writerActive = true return true } func (m *RWMutex) TryRLock() bool { - ok := m.mutex.TryLock() - if !ok { - return false - } + m.mutex.Lock() defer m.mutex.Unlock() - m.underRLock() - - return true -} - -func (m *RWMutex) underLock() { - m.writersWaiting++ - for m.writerActive || m.readerCount != 0 { - m.writerCond.Wait() + if m.writerActive || m.writersWaiting > 0 { + return false } - m.writerActive = true - m.writersWaiting-- -} -func (m *RWMutex) underRLock() { - for m.writerActive || m.writersWaiting > 0 { - m.writerCond.Wait() - } m.readerCount++ + return true } diff --git a/homeworks/13_sync_primitives/homework_test.go b/homeworks/13_sync_primitives/homework_test.go index 67d331b..53ce4dd 100644 --- a/homeworks/13_sync_primitives/homework_test.go +++ b/homeworks/13_sync_primitives/homework_test.go @@ -100,3 +100,39 @@ func TestRWMutexWithWriterPriority(t *testing.T) { assert.True(t, mutualExlusionWithWriter.Load()) assert.Equal(t, int32(1), readersCount.Load()) } + +func TestTryLockFailsWhenWriterActive(t *testing.T) { + mutex := NewRWMutex() + mutex.Lock() // writer + + ok := mutex.TryLock() + assert.False(t, ok) +} + +func TestTryLockFailsWhenReadersActive(t *testing.T) { + mutex := NewRWMutex() + mutex.RLock() // reader + + ok := mutex.TryLock() + assert.False(t, ok) +} + +func TestTryLockSucceedsWhenFree(t *testing.T) { + mutex := NewRWMutex() + + ok := mutex.TryLock() + assert.True(t, ok) + + var entered atomic.Bool + entered.Store(false) + + go func() { + mutex.Lock() + entered.Store(true) + }() + + time.Sleep(100 * time.Millisecond) + assert.False(t, entered.Load()) + + mutex.Unlock() +}