sync: implement trylock
Этот коммит содержится в:
родитель
45764325b4
коммит
cb39611389
2 изменённых файлов: 71 добавлений и 5 удалений
|
@ -3,10 +3,12 @@ package sync
|
||||||
import (
|
import (
|
||||||
"internal/task"
|
"internal/task"
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mutex struct {
|
type Mutex struct {
|
||||||
locked bool
|
state uint8 // Set to non-zero if locked.
|
||||||
blocked task.Stack
|
blocked task.Stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,18 +16,18 @@ type Mutex struct {
|
||||||
func scheduleTask(*task.Task)
|
func scheduleTask(*task.Task)
|
||||||
|
|
||||||
func (m *Mutex) Lock() {
|
func (m *Mutex) Lock() {
|
||||||
if m.locked {
|
if m.islocked() {
|
||||||
// Push self onto stack of blocked tasks, and wait to be resumed.
|
// Push self onto stack of blocked tasks, and wait to be resumed.
|
||||||
m.blocked.Push(task.Current())
|
m.blocked.Push(task.Current())
|
||||||
task.Pause()
|
task.Pause()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.locked = true
|
m.setlock(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mutex) Unlock() {
|
func (m *Mutex) Unlock() {
|
||||||
if !m.locked {
|
if !m.islocked() {
|
||||||
panic("sync: unlock of unlocked Mutex")
|
panic("sync: unlock of unlocked Mutex")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,10 +35,38 @@ func (m *Mutex) Unlock() {
|
||||||
if t := m.blocked.Pop(); t != nil {
|
if t := m.blocked.Pop(); t != nil {
|
||||||
scheduleTask(t)
|
scheduleTask(t)
|
||||||
} else {
|
} else {
|
||||||
m.locked = false
|
m.setlock(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TryLock tries to lock m and reports whether it succeeded.
|
||||||
|
//
|
||||||
|
// Note that while correct uses of TryLock do exist, they are rare,
|
||||||
|
// and use of TryLock is often a sign of a deeper problem
|
||||||
|
// in a particular use of mutexes.
|
||||||
|
func (m *Mutex) TryLock() bool {
|
||||||
|
if m.islocked() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
m.Lock()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mutex) islocked() bool {
|
||||||
|
return volatile.LoadUint8(&m.state) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mutex) setlock(b bool) {
|
||||||
|
volatile.StoreUint8(&m.state, boolToU8(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolToU8(b bool) uint8 {
|
||||||
|
if b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type RWMutex struct {
|
type RWMutex struct {
|
||||||
// waitingWriters are all of the tasks waiting for write locks.
|
// waitingWriters are all of the tasks waiting for write locks.
|
||||||
waitingWriters task.Stack
|
waitingWriters task.Stack
|
||||||
|
|
|
@ -7,6 +7,42 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func HammerMutex(m *sync.Mutex, loops int, cdone chan bool) {
|
||||||
|
for i := 0; i < loops; i++ {
|
||||||
|
if i%3 == 0 {
|
||||||
|
if m.TryLock() {
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m.Lock()
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
cdone <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMutex(t *testing.T) {
|
||||||
|
m := new(sync.Mutex)
|
||||||
|
|
||||||
|
m.Lock()
|
||||||
|
if m.TryLock() {
|
||||||
|
t.Fatalf("TryLock succeeded with mutex locked")
|
||||||
|
}
|
||||||
|
m.Unlock()
|
||||||
|
if !m.TryLock() {
|
||||||
|
t.Fatalf("TryLock failed with mutex unlocked")
|
||||||
|
}
|
||||||
|
m.Unlock()
|
||||||
|
|
||||||
|
c := make(chan bool)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go HammerMutex(m, 1000, c)
|
||||||
|
}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
<-c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestMutexUncontended tests locking and unlocking a Mutex that is not shared with any other goroutines.
|
// TestMutexUncontended tests locking and unlocking a Mutex that is not shared with any other goroutines.
|
||||||
func TestMutexUncontended(t *testing.T) {
|
func TestMutexUncontended(t *testing.T) {
|
||||||
var mu sync.Mutex
|
var mu sync.Mutex
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче