部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

go笔记-并发赋值安全性

参考资料

https://cloud.tencent.com/developer/article/1810536

并发赋值安全/不安全的类型

  1. 并发赋值安全的类型:
    字节型,布尔型、整型、浮点型、字符型、指针、函数
    这些类型可由一条机器指令完成赋值

  2. 数组由一个或多个元素组成,大部分情况并发不安全
    注意:当位宽不大于 64 位且是 2 的整数次幂(8,16,32,64),那么其并发赋值是安全的。

  3. struct 或底层是 struct 的类型并发赋值大部分情况并发不安全,类型有:
    复数、字符串、 数组、切片、字典、通道、接口
    注:当 struct 赋值时退化为单个字段由一个机器指令完成赋值时,并发赋值又是安全的。这种情况有:
    3.1 实部或虚部相同的复数的并发赋值
    3.2 等长字符串的并发赋值
    3.3 同长度同容量切片的并发赋值
    3.4 同一种具体类型不同值并发赋给接口

例3.1: 实部或虚部相同的复数的并发赋值

// 线程不安全
var g complex64
go func() {
	g = complex(1, 2)
}()

go func() {
	g = complex(3, 4)
}()
// 线程安全
var g complex64
go func() {
	g = complex(1, 2)
}()

go func() {
	g = complex(1, 3)  // 实部相同
}()

例3.2 等长字符串的并发赋值

// 线程不安全
var s string
go func() {
	s = "ab"
}()
go func() {
	s = "abc"
}()
// 线程安全
var s string
go func() {
	s = "abc"
}()
go func() {
	s = "abd"  // 字符串长度相同, 线程安全
}()

完整例子

点击打开完整示例
func main() {
	var s string
	i := 0
	for {
		var wg sync.WaitGroup
		var endWg sync.WaitGroup
		// 协程 1
		endWg.Add(2)
		wg.Add(1)
		go func() {
			wg.Wait()
			s = "ab"
			endWg.Done()
		}()

		// 协程 2
		go func() {
			wg.Wait()
			s = "abc"
			endWg.Done()
		}()
		wg.Done()    // 协程内同时进行赋值
		endWg.Wait() // 等待两次并发赋值完成

		i++
		// 赋值异常判断
		if s != "ab" && s != "abc" {
			fmt.Printf("concurrent assignment error, i=%v s=%v", i, s)
			break
		}
	}
}
posted @ 2023-01-30 20:08  流了个火  阅读(229)  评论(0编辑  收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats