目录

Mutex

type Mutex struct {
    state int32    // 表示互斥锁的状态,比如是否被锁定等
    sema  uint32   // 信号量,协程阻塞等待该信号量,解锁的协程释放信号量从而唤醒等待信号量的协程
}

type RWMutex struct {
    w           Mutex  //用于控制多个写锁,获得写锁首先要获取该锁,如果有一个写锁在进行,那么再到来的写锁将会阻塞于此
    writerSem   uint32 //写阻塞等待的信号量,最后一个读者释放锁时会释放信号量
    readerSem   uint32 //读阻塞的协程等待的信号量,持有写锁的协程释放锁后会释放信号量
    readerCount int32  //记录读者个数
    readerWait  int32  //记录写阻塞时读者个数
}

通过临界区来保护共享资源

var wg sync.WaitGroup
var counter int
var mu sync.Mutex

func main() {

    wg.Add(2)
    go incCounter(1)
    go incCounter(2)
    wg.Wait()

    fmt.Println("Final Counter : ", counter)
}

func incCounter(id int) {
    defer wg.Done()
    for count := 0; count < 2; count++ {
        mu.Lock() // ------------------ 临界区 ------------------
        {
            value := counter
            runtime.Gosched()
            value++
            counter = value
        }
        mu.Unlock() // ----------------------------------------
    }
}

Atomic

var wg sync.WaitGroup
var counter int64

func main() {

    wg.Add(2)
    go incCounter(1)
    go incCounter(2)
    wg.Wait()

    fmt.Println("Final Counter:", counter)
}

func incCounter(id int) {
    defer wg.Done()
    for count := 0; count < 2; count++ {
        atomic.AddInt64(&counter, 1) // 原子性 +1
        runtime.Gosched()            // 本Goroutine让出计算资源
    }
}
// 通过共享变量来控制Goroutine运行
var wg sync.WaitGroup
var shutdown int64

func main() {

    wg.Add(2)
    go doWork("A")
    go doWork("B")
    time.Sleep(time.Second)
    fmt.Println("Shutdown Now")
    atomic.StoreInt64(&shutdown, 1)
    wg.Wait()
}

func doWork(name string) {
    defer wg.Done()
    for {
        fmt.Println("Doing ", name, " Work ")
        time.Sleep(250 * time.Millisecond)
        if atomic.LoadInt64(&shutdown) == 1 {
            fmt.Println("Work ", name, " Shutting Down")
            break
        }
    }
}

Channel控制同步

模拟乒乓球赛


var wg sync.WaitGroup

func init() {
const (
    numberGoroutines = 4
    taskLoad         = 20
)

var (
    wg sync.WaitGroup
)

func init() {
    rand.Seed(time.Now().Unix())
}

func main() {

    taskChan := make(chan string, taskLoad)

    for workerID := 0; workerID < numberGoroutines; workerID++ {
        wg.Add(1)
        go worker(taskChan, workerID)
    }

    for post := 1; post <= taskLoad; post++ {
        taskChan <- fmt.Sprintf("Task : %d", post)
    }

    close(taskChan)

    wg.Wait()
}

func worker(taskChan chan string, worker int) {
    defer wg.Done()
    for {
        task, ok := <-taskChan
        if !ok {
            fmt.Println("worker ", worker, " shutding down")
            return
        }
        fmt.Println("worker ", worker, " start task ", task)
        time.Sleep(time.Duration(rand.Int63n(100)) * time.Millisecond)
        fmt.Println("worker ", worker, " Complete task ", task)
    }
}

    rand.Seed(time.Now().UnixNano())
}

// 模拟乒乓球塞
func main() {
    court := make(chan int)

    wg.Add(1)
    go player("Link", court) // Link 准备接球
    court <- 1               // 裁判发球

    wg.Add(1)
    go player("Max", court) // Max 准备接 Link 打过来的球

    wg.Wait()
}

func player(name string, court chan int) {
    defer wg.Done()

    for {
        ball, ok := <-court
        if !ok {
            fmt.Println("Player ", name, " won")
            return
        }

        time.Sleep(time.Second / 2)
        n := rand.Intn(100)
        // 被 13 整除表示输球
        if n%13 == 0 {
            fmt.Println("Player ", name, " Missed")
            close(court)
            return
        }
        fmt.Printf("Player %s Hit %d \n", name, ball)

        ball++
        court <- ball
    }
}

const (
    numberGoroutines = 4
    taskLoad         = 20
)

var (
    wg sync.WaitGroup
)

func init() {
    rand.Seed(time.Now().Unix())
}

func main() {

    taskChan := make(chan string, taskLoad)

    for workerID := 0; workerID < numberGoroutines; workerID++ {
        wg.Add(1)
        go worker(taskChan, workerID)
    }

    for post := 1; post <= taskLoad; post++ {
        taskChan <- fmt.Sprintf("Task : %d", post)
    }

    close(taskChan) // 关闭的通道,读取直接返回零值 ok 为 false; 未关闭,则是阻塞等待

    wg.Wait()
}

func worker(taskChan chan string, worker int) {
    defer wg.Done()
    for {
        task, ok := <-taskChan
        if !ok {
            fmt.Println("worker ", worker, " shutding down")
            return
        }
        fmt.Println("worker ", worker, " start task ", task)
        time.Sleep(time.Duration(rand.Int63n(100)) * time.Millisecond)
        fmt.Println("worker ", worker, " Complete task ", task)
    }
}

关闭的通道,读取它直接返回零值 okfalse; 未关闭,则是阻塞等待