Go语言第十五课 共享内存和竞争机制——锁

互斥锁

使用sync.Mutex可以实现“临界区”。

进入临界区之前尝试sync.Mutex.Lock(),如果没有被其他协程锁住,当前协程将获得一个互斥锁。如果被其他协程先锁住,这个操作将会被阻塞直到其他的协程释放了这个互斥锁。

执行完临界区代码之后需要调用sync.Mutex.Unlock()释放互斥锁。

package main

import (
	"fmt"
	"sync"
	"bufio"
	"os"
	"time"
)

func main() {
	lock := new(sync.Mutex)
	go test(lock, 1)
	go test(lock, 2)
	go test(lock, 3)
	go test(lock, 4)
	go test(lock, 5)
	go test(lock, 6)
	go test(lock, 7)
	go test(lock, 8)
	bufio.NewReader(os.Stdin).ReadString('\n')
}

func test(lock *sync.Mutex, index int) {
	defer lock.Unlock()
	lock.Lock()
	fmt.Printf("test start %d\n", index)
	time.Sleep(5 * time.Second)
	fmt.Printf("test end %d\n", index)
}
test start 4
test end 4
test start 2
test end 2
test start 1
test end 1
test start 6
test end 6
test start 5
test end 5
test start 3
test end 3
test start 7
test end 7
test start 8

test end 8

如果取消互斥锁,即将Lock()和Unlock()注释掉,结果为

test start 3
test start 5
test start 4
test start 8
test start 7
test start 1
test start 2
test start 6
test end 6
test end 3
test end 5
test end 4
test end 8
test end 7
test end 1
test end 2

读写锁

package main

import (
	"fmt"
	"sync"
	"bufio"
	"os"
	"time"
)

var testCount = 0

func main() {
	lock := new(sync.RWMutex)
	go test_read(lock, 1)
	go test_write(lock, 1)
	go test_read(lock, 2)
	go test_write(lock, 2)
	go test_read(lock, 3)
	go test_write(lock, 3)
	go test_read(lock, 4)
	go test_write(lock, 4)
	go test_read(lock, 5)
	go test_write(lock, 5)
	go test_read(lock, 6)
	go test_write(lock, 6)
	bufio.NewReader(os.Stdin).ReadString('\n')
}

func test_read(lock *sync.RWMutex, index int) {
	defer lock.RUnlock()
	lock.RLock()
	fmt.Printf("test_read start %d\n", index)
	time.Sleep(4 * time.Second)
	fmt.Printf("read value is %d\n", testCount)
	fmt.Printf("test_read end %d\n", index)
}

func test_write(lock *sync.RWMutex, index int) {
	defer lock.Unlock()
	lock.Lock()
	fmt.Printf("test_write start %d\n", index)
	time.Sleep(2 * time.Second)
	testCount += 1
	fmt.Printf("write value is %d\n", testCount)
	fmt.Printf("test_write end %d\n", index)
}
test_read start 3
read value is 0
test_read end 3
test_write start 4
write value is 1
test_write end 4
test_read start 4
test_read start 6
test_read start 1
test_read start 2
test_read start 5
read value is 1
test_read end 5
read value is 1
test_read end 4
read value is 1
test_read end 6
read value is 1
test_read end 1
read value is 1
test_read end 2
test_write start 3
write value is 2
test_write end 3
test_write start 1
write value is 3
test_write end 1
test_write start 2
write value is 4
test_write end 2
test_write start 5
write value is 5
test_write end 5
test_write start 6
write value is 6
test_write end 6

对结果稍加分析可以看出,执行顺序是这样的:

读3,写4等待

写4,读4、6、1、2、5等待

读5、4、6、1、2,写3等待

写3,写1等待

写1,写2等待

写2,写5等待

写5,写6等待

写6

总结:读的时候,可读不可写!写的时候,不可读不可写!

构造锁

package main

import (
	"fmt"
	"sync"
	"time"
	"bufio"
	"os"
)

var testCount = 0

func main() {
	once_lock := new(sync.Once)
	go go_test(once_lock, 1)
	go go_test(once_lock, 2)
	go go_test(once_lock, 3)
	go go_test(once_lock, 4)
	bufio.NewReader(os.Stdin).ReadString('\n')
}

func go_test(once *sync.Once, index int) {
	fmt.Printf("go_test %d start\n", index)
	once.Do(test_one)
	fmt.Printf("go_test %d end\n", index)
}

func test_one() {
	fmt.Printf("------------test_one start\n")
	time.Sleep(5 * time.Second)
	fmt.Printf("------------test_one end\n")
}
go_test 1 start
------------test_one start
go_test 3 start
go_test 2 start
go_test 4 start
------------test_one end
go_test 1 end
go_test 2 end
go_test 3 end
go_test 4 end

由此可见,sync.Once可以保证传入的函数只做一遍。所以这个锁的这种特别设计常用于代价稍大的初始化。


猜你喜欢

转载自blog.csdn.net/yongyu_it/article/details/80895202