Golang Go语言中大佬请进,三协程按序打印 abc 到底哪里出错
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
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(5time.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(&c.sema1, 1, 0) // printC()<br>println("B") // printB()<br>atomic.CompareAndSwapInt32(&c.sema2, 1, 0) // printC()<br>atomic.CompareAndSwapInt32(&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(&c.sema1,0,1) } }<br><br>}<br><br>func (c *cond)printB(){ for { if c.sema1==1&& c.sema2==0{ println("B") atomic.CompareAndSwapInt32(&c.sema2,0,1) } } }<br><br>func (c *cond) printC(){ for { if c.sema2==1 { println("C") println("--------------------------------") atomic.CompareAndSwapInt32(&c.sema1, 1, 0) atomic.CompareAndSwapInt32(&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(&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(&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(&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,确保通道中最多只有一个元素。每个协程在打印完其字符后,向通道发送一个空结构体来通知下一个协程可以继续执行。
如果你的代码没有按序打印,请检查以下几点:
- 确保通道被正确使用,并且没有死锁。
- 确保所有的协程都被正确同步。
- 使用
sync.WaitGroup
来等待所有协程完成。
希望这些信息对你有帮助!