Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Concurrency 为什么这个程序在我的系统上终止,而不是在操场上终止?_Concurrency_Go_Undefined Behavior - Fatal编程技术网

Concurrency 为什么这个程序在我的系统上终止,而不是在操场上终止?

Concurrency 为什么这个程序在我的系统上终止,而不是在操场上终止?,concurrency,go,undefined-behavior,Concurrency,Go,Undefined Behavior,考虑一下这个计划: package main import "fmt" import "time" import "runtime" func main() { x := 0 go func() { time.Sleep(500 * time.Millisecond) x = 1 }() for x == 0 { runtime.Gosched() } fmt.Println("it wo

考虑一下这个计划:

package main

import "fmt"
import "time"
import "runtime"

func main() {

    x := 0

    go func() {
        time.Sleep(500 * time.Millisecond)
        x = 1
    }()

    for x == 0 {
        runtime.Gosched()
    }

    fmt.Println("it works!")
}

为什么它在本地终止,而不是在上终止?我的程序的终止是否依赖于未定义的行为?

围棋场使用了一种特殊的
time.Sleep实现,旨在防止单个程序垄断网站的后端资源

如中所述,调用time.Sleep()的goroutine将处于睡眠状态。游乐场后端等待所有其他goroutine被阻止(否则将是死锁),然后以最短的超时时间唤醒goroutine


在您的程序中,有两个goroutine:主goroutine和调用
time.Sleep
的goroutine。由于主goroutine从不阻塞,
time.Sleep
调用将永远不会返回。程序继续运行,直到超过分配给它的CPU时间,然后终止。

该代码不能提供太多保证。它几乎完全依赖于未定义行为的实现细节

在大多数多线程系统中,不能保证在一个线程中没有障碍的更改会在另一个线程中看到。你有一个goroutine,它可以运行在另一个处理器上,向一个变量写入一个值,而这个变量从来没有人保证读取过

x==0{
可以很容易地重写为{
,因为无法保证该变量的任何更改都是可见的


竞赛检测器也可能会报告此问题。您真的不应该期望它起作用。如果您想要一个
sync.WaitGroup
,您应该只使用一个,因为它正确地跨线程协调。

Go内存模型不能保证主程序会观察到写入goroutine中x的值。a s类似错误的程序在上一节中给出了一个例子。Go内存模型还特别调用了没有同步的繁忙等待,这在中是一个不正确的习惯用法

您需要在goroutine中执行某种类型的同步,以确保x=1发生在main中for循环的某个迭代之前

这是一个保证按预期工作的程序版本

主程序包
进口(
“fmt”
“时间”
)
func main(){
c:=制造(陈布尔)
x:=0
go func(){
时间。睡眠(500*时间。毫秒)
x=1
关闭(c)//1
}()
对于x==0{

这在C中可能是正确的,但在Go中,有一些东西可能会修改x的值;其中之一是Go例程中的赋值。一个优化检查的编译器是错误的。显然,忙碌的等待确实在Go中。不过,我之前的评论仍然成立。@fuzzxl:这不是优化检查的情况。请参阅我的答案了解w为什么这段代码保证不会在操场上运行。不,一个编译器优化一种没有障碍的检查方法不是错误的,代码是错误的。如果你写了正确的代码,而编译器让一些意想不到的事情发生,你可以责怪编译器。Go内置的种族检测器非常清楚、容易地告诉你你的代码是错误的:对。但是你可以ld在没有内存竞争的情况下重写程序(例如,添加互斥锁,使用原子操作)由于特殊的
时间。Sleep
实现,它仍然会在操场上失败。+1用于解释程序在操场上失败的原因。我发布了一个答案,试图解释为什么程序不能保证在一般情况下正常工作(基于Go内存模型的规则)。
package main

import (
    "fmt"
    "time"
)

func main() {
    c := make(chan bool)
    x := 0

    go func() {
        time.Sleep(500 * time.Millisecond)
        x = 1
        close(c) // 1
    }()

    for x == 0 {
        <-c // 2
    }

    fmt.Println("it works!")
}