goroutine竞争状态的两种解决办法(原子函数与互斥锁)

以下代码均运行通过

package main

import (
	"fmt"
	"runtime"
	"sync"
	"sync/atomic"
)

//计数器(竞争资源)
var counter int64

//wg用来等待程序完成
var wg sync.WaitGroup

//互斥锁
var mutex sync.Mutex

func main() {
	//分配一个逻辑处理器给调度器使用
	runtime.GOMAXPROCS(1)

	//引用计数+2,便是要等待两个goroutine
	wg.Add(2)
	fmt.Println("Start Gorountines")

	var cse = 0 //可根据要求更改cse值,查看相应的运行就结果

	//创建两个gorountine
	switch cse {
	case 0: //竞争状态
		go incCounterA(1)
		go incCounterA(2)
	case 1: //原子函数
		go incCounterB(1)
		go incCounterB(2)
	case 2: //互斥锁
		go incCounterC(1)
		go incCounterC(2)
	}

	//等待goroutine结束
	fmt.Println("Wait To Finish")
	wg.Wait()
	fmt.Println("Terminating Program")
}

func incCounterA(cntId int) {
	defer wg.Done()

	for count := 0; count < 2; count++ {
		//捕获counter的值
		value := counter
		fmt.Printf("ID=%d_A cnter=%d\n", cntId, counter)
		//当前goroutine从线程退出,并放回到队列
		runtime.Gosched()
		//增加本地value变量的值
		value++
		counter = value
		fmt.Printf("ID=%d_B cnter=%d\n", cntId, counter)
	}
}

func incCounterB(cntId int) {
	defer wg.Done()

	for count := 0; count < 2; count++ {
		fmt.Printf("ID=%d_A cnter=%d\n", cntId, counter)
		atomic.AddInt64(&counter, 1)
		//当前goroutine从线程退出,并放回到队列
		runtime.Gosched()
		fmt.Printf("ID=%d_B cnter=%d\n", cntId, counter)
	}
}

func incCounterC(cntId int) {
	defer wg.Done()

	for count := 0; count < 2; count++ {
		//同一时刻,只允许一个goroutine进入临界区
		mutex.Lock()
		{
			//捕获counter的值
			value := counter
			fmt.Printf("ID=%d_A cnter=%d\n", cntId, counter)
			//当前goroutine从线程退出,并放回到队列
			runtime.Gosched()
			//增加本地value变量的值
			value++
			counter = value
			fmt.Printf("ID=%d_B cnter=%d\n", cntId, counter)

		}
		//释放锁,允许其他等待的gorutine进入临界区
		mutex.Unlock()
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值