Golang中实现互斥锁的Tie-breaker算法遇到问题求助

Golang中实现互斥锁的Tie-breaker算法遇到问题求助 Screenshot 2023-04-01 at 14.06.37

var data int = 1
var done = make(chan bool)

var last int = 1
var in1 bool = false
var in2 bool = false
var mu sync.Mutex

func racing1() {
	for i := 0; i < 10000; i++ {
		last = 1
		in1 = true

		for in2 && last == 1 {
		}
		// mu.Lock()
		data = data + 1
		// mu.Unlock()

		in1 = false
	}

	done <- true
}

func racing2() {
	for i := 0; i < 10000; i++ {
		last = 2
		in2 = true

		for in1 && last == 2 {
		}

		// mu.Lock()
		data = data + 1
		// mu.Unlock()

		in2 = false
	}

	done <- true
}

func main() {
	go racing1()
	go racing2()

	<-done
	<-done

	fmt.Println(data)
}

更多关于Golang中实现互斥锁的Tie-breaker算法遇到问题求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

是的。我已经确认,如果存在数据竞争,常见的编程语言并不能保证顺序一致性。

无论如何,感谢!

更多关于Golang中实现互斥锁的Tie-breaker算法遇到问题求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go Gopher Logo

Go 内存模型 - Go 编程语言

修改被多个 goroutine 同时访问的数据的程序必须序列化此类访问。

这个代码实现的是Peterson算法,用于两个goroutine之间的互斥访问。问题在于没有正确实现内存可见性保证,导致竞争条件。

主要问题:

  1. Go的内存模型不保证goroutine间的变量可见性
  2. 缺少内存屏障或同步原语
  3. 编译器/CPU可能对循环进行优化

正确实现需要添加内存屏障或使用atomic操作:

package main

import (
	"fmt"
	"sync/atomic"
)

var data int32 = 1
var done = make(chan bool)

var last int32 = 1
var in1 int32 = 0
var in2 int32 = 0

func racing1() {
	for i := 0; i < 10000; i++ {
		atomic.StoreInt32(&last, 1)
		atomic.StoreInt32(&in1, 1)

		for atomic.LoadInt32(&in2) == 1 && atomic.LoadInt32(&last) == 1 {
			// 忙等待
		}
		
		atomic.AddInt32(&data, 1)
		
		atomic.StoreInt32(&in1, 0)
	}
	done <- true
}

func racing2() {
	for i := 0; i < 10000; i++ {
		atomic.StoreInt32(&last, 2)
		atomic.StoreInt32(&in2, 1)

		for atomic.LoadInt32(&in1) == 1 && atomic.LoadInt32(&last) == 2 {
			// 忙等待
		}
		
		atomic.AddInt32(&data, 1)
		
		atomic.StoreInt32(&in2, 0)
	}
	done <- true
}

func main() {
	go racing1()
	go racing2()

	<-done
	<-done

	fmt.Println(atomic.LoadInt32(&data))
}

或者使用sync包提供的互斥锁:

package main

import (
	"fmt"
	"sync"
)

var data int = 1
var done = make(chan bool)
var mu sync.Mutex

func racing1() {
	for i := 0; i < 10000; i++ {
		mu.Lock()
		data = data + 1
		mu.Unlock()
	}
	done <- true
}

func racing2() {
	for i := 0; i < 10000; i++ {
		mu.Lock()
		data = data + 1
		mu.Unlock()
	}
	done <- true
}

func main() {
	go racing1()
	go racing2()

	<-done
	<-done

	fmt.Println(data)
}

Peterson算法在Go中需要atomic操作来保证内存可见性,否则会出现数据竞争和不正确的结果。

回到顶部