Go并发编程--基于channel信号量来实现互斥锁

概述

根据前面的一片文章:《Go并发编程–通过channel来实现信号量原语》我们实现了信号量的基本原语P和V操作,本章介绍如何通过P操作和V操作来实现互斥锁。

实现原理

当我们把channel的容量设置为1时,P和V操作就变成了,lock和unlock操作。为什么呢?我们来看下代码实现:

/* mutexes */
func (s semaphore) Lock() {
    s.P(1)
}

func (s semaphore) Unlock() {
    s.V(1)
}

上篇讲过P和V操作的实现,当channel的容量只有一个,此时P和V的数量变为1时,进行P操作的协程只能有一个,在该协程执行完P操作没有执行V操作时,其他协程只能等待,这样就实现了只能有一个协程访问临界区的功能。

完整代码

package main

import (
    "fmt"
    "os"
    "time"
)

type Empty interface {}
type semaphore chan Empty

// 实现信号量原语
// acquire n resources
func (s semaphore) P(n int) {
    e := new(Empty)
    for i := 0; i < n; i++ {
        s <- e
    }
}

// release n resources
func (s semaphore) V(n int) {
    for i := 0; i < n; i++ {
        <-s
    }
}

// 通过以上原语实现互斥锁
/* mutexes */
func (s semaphore) Lock() {
    s.P(1)
}

func (s semaphore) Unlock() {
    s.V(1)
}

// 工作协程,这里只是打印0-99的整数
func printInt(sem semaphore) {
    sem.Lock()
    for i := 0; i < 100; i++ {
        fmt.Fprintf(os.Stderr, "%d\n", i)
    }
    sem.Unlock()
}

func main()  {
    sem := make(semaphore, 1)

    go printInt(sem)
    go printInt(sem)

    // 等待两个goroutine结束
    time.Sleep(10e9)
    fmt.Fprintf(os.Stderr, "end\n")
}

当channel容量时1是,就只能有一个协程能完成P操作,直到该协程完成了V操作,其他协程才能进行P操作,这样就实现了互斥锁。

总结

通过channel实现的信号量原语,我们实现了互斥锁。通过P和V原语我们还能实现信号量的一些操作,从而更好的控制协程间的通信。如何实现信号量操作,请继续看后面的文章。

猜你喜欢

转载自blog.csdn.net/zg_hover/article/details/81049729