Golang Go语言中大佬请进,三协程按序打印 abc 到底哪里出错

发布于 1周前 作者 eggper 来自 Go语言

Golang Go语言中大佬请进,三协程按序打印 abc 到底哪里出错

这段代码的问题在于大部分情况是 ABC 按序输出的,但有时候 A 协程没有打印 A,结果变成了 BC

type cond struct{ sema1 int32 sema2 int32 } func (c *cond)printA(){ for { if c.sema1==0{ println("A") atomic.CompareAndSwapInt32(&c.sema1,0,1) } }

}

func (c *cond)printB(){ for { if c.sema1==1&& c.sema2==0{ println("B") atomic.CompareAndSwapInt32(&c.sema2,0,1) } } }

func (c *cond) printC(){ for { if c.sema2==1 { println("C") println("--------------------------------") atomic.CompareAndSwapInt32(&c.sema1, 1, 0) atomic.CompareAndSwapInt32(&c.sema2, 1, 0) } } }

func main() { var con =new (cond) con.sema1=0 con.sema2=0 go con.printC() go con.printB() go con.printA() time.Sleep(5*time.Second)

}


更多关于Golang Go语言中大佬请进,三协程按序打印 abc 到底哪里出错的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

17 回复

type cond struct{
sema1 int32
sema2 int32
}
func (c *cond)printA(){
for {
if c.sema1==0{
println(“A”)
atomic.CompareAndSwapInt32(&c.sema1,0,1)
}
}

}

func (c *cond)printB(){
for {
if c.sema1==1&& c.sema2==0{
println(“B”)
atomic.CompareAndSwapInt32(&c.sema2,0,1)
}
}
}


func (c cond) printC(){
for {
if c.sema2==1 {
println(“C”)
println("--------------------------------")
atomic.CompareAndSwapInt32(&c.sema1, 1, 0)
atomic.CompareAndSwapInt32(&c.sema2, 1, 0)
}
}
}

func main() {
var con =new (cond)
con.sema1=0
con.sema2=0
go con.printC()
go con.printB()
go con.printA()
time.Sleep(5
time.Second)

}

更多关于Golang Go语言中大佬请进,三协程按序打印 abc 到底哪里出错的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


友情提示, v 站支持 Markdown

谢谢,我也会用管道,只是想试试这种无锁变量的方法

第一次发帖哈哈

printC() 执行了 2 次 atomic 操作,但这两次操作的整体过程显然并不是原子的

go<br>println("C") // printC()<br>println("--------------------------------") // printC()<br>atomic.CompareAndSwapInt32(&amp;c.sema1, 1, 0) // printC()<br>println("B") // printB()<br>atomic.CompareAndSwapInt32(&amp;c.sema2, 1, 0) // printC()<br>atomic.CompareAndSwapInt32(&amp;c.sema2, 0, 1) // printB()<br>println("C") // printC(), 下一次循环<br>println("--------------------------------") // printC()<br>

go<br>type cond struct{ sema1 int32 sema2 int32 } func (c *cond)printA(){ for { if c.sema1==0{ println("A") atomic.CompareAndSwapInt32(&amp;c.sema1,0,1) } }<br><br>}<br><br>func (c *cond)printB(){ for { if c.sema1==1&amp;&amp; c.sema2==0{ println("B") atomic.CompareAndSwapInt32(&amp;c.sema2,0,1) } } }<br><br>func (c *cond) printC(){ for { if c.sema2==1 { println("C") println("--------------------------------") atomic.CompareAndSwapInt32(&amp;c.sema1, 1, 0) atomic.CompareAndSwapInt32(&amp;c.sema2, 1, 0) } } }<br><br>func main() { var con =new (cond) con.sema1=0 con.sema2=0 go con.printC() go con.printB() go con.printA() time.Sleep(5*time.Second)<br><br>}<br>

您是对的,已解决

我运行了好多遍楼主的代码,结果都是

A
B
C
--------------------------------
A
B
C
--------------------------------
A
B
C
--------------------------------
A
B
C
--------------------------------

这样输出,没有出现其他情况,楼主你说「但有时候 A 协程没有打印 A,结果变成了 BC 」

是什么样子的输出结果,可以解释一下吗

用一个信号量就行了

<br>const (<br> printA = iota<br> printB<br> printC<br>)<br><br>type cond struct{<br> sema int32<br>}<br>func (c *cond)printA(){<br> for {<br> if c.sema == printA{<br> println("A")<br> swapInt32 := atomic.CompareAndSwapInt32(&amp;c.sema, 0, printB)<br> if !swapInt32 {<br> panic("A")<br> }<br> }<br> }<br><br>}<br><br>func (c *cond)printB(){<br> for {<br> if c.sema == printB{<br> println("B")<br> if !atomic.CompareAndSwapInt32(&amp;c.sema,printB,printC) {<br> panic("B")<br> }<br> }<br> }<br>}<br><br><br>func (c *cond) printC(){<br> for {<br> if c.sema==printC {<br> println("C")<br> println("--------------------------------")<br> if !atomic.CompareAndSwapInt32(&amp;c.sema, printC, printA) {<br> panic("C")<br> }<br> }<br> }<br>}<br><br>func main() {<br> var con =new (cond)<br> go con.printC()<br> go con.printB()<br> go con.printA()<br> time.Sleep(5*time.Second)<br><br>}<br>

按照楼上所说 printC 里即使两次不是原子操作,由于先执行的 CAS(sem1, 1, 0),此时 sema1=0, sema2=1,
应该也不会触发 printB 的条件(sema1=1,sema2=0)吧,为何会走进下面的 printB 逻辑里。

cpu 有可能乱序执行,所以要加锁确保执行顺序如代码所示

就是出现 A 没有打印的情况,比较少,但是有,建议这题采取 channel 的方式来做,上面有人给了很好的示例

#12 虽然锅基本会落在乱序执行上,但我给的那个答案的确不对。。

#12
#14

应该是 printB() 的判断的两个部分分别落在了 pinrtC() 的两个 cas 的前后

在Golang中,使用协程(goroutine)按序打印 a, b, c 可以通过多种同步机制来实现,比如使用通道(channel)和 sync 包中的工具。如果你遇到按序打印失败的问题,很可能是同步机制没有正确使用。

一个常见的方法是使用带缓冲的通道来同步协程的执行顺序。下面是一个简单的示例代码,展示了如何按序打印 a, b, c

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	ch := make(chan struct{}, 1) // 带缓冲的通道,容量为1

	wg.Add(3)

	go func() {
		defer wg.Done()
		fmt.Print("a")
		ch <- struct{}{}
	}()

	go func() {
		defer wg.Done()
		<-ch
		fmt.Print("b")
		ch <- struct{}{}
	}()

	go func() {
		defer wg.Done()
		<-ch
		fmt.Print("c")
	}()

	wg.Wait()
}

在这个例子中,我们创建了一个带缓冲的通道 ch,容量为1,确保通道中最多只有一个元素。每个协程在打印完其字符后,向通道发送一个空结构体来通知下一个协程可以继续执行。

如果你的代码没有按序打印,请检查以下几点:

  1. 确保通道被正确使用,并且没有死锁。
  2. 确保所有的协程都被正确同步。
  3. 使用 sync.WaitGroup 来等待所有协程完成。

希望这些信息对你有帮助!

回到顶部