Why does this program terminate on my system but not on playground?

风格不统一 提交于 2019-12-23 19:24:09

问题


Consider this program:

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!")
}

Why does it terminate locally but not on Playground? Does the termination of my program rely on undefined behavior?


回答1:


That code doesn't offer much guarantees. It's relying almost entirely on implementation details around undefined behavior.

In most multi-threaded systems, there's no guarantee that a change in one thread with no barrier will be seen in another. You've got a goroutine which could be running on another processor altogether writing a value to a variable nobody's ever guaranteed to read.

The for x == 0 { could quite easily be rewritten to for { since there's never a guarantee any changes to that variable might be visible.

The race detector will also probably report this issue. You should really not expect this to work. If you want a sync.WaitGroup you should just use one as it properly coordinates across threads.




回答2:


The Go playground uses a special implementation of time.Sleep designed to prevent individual programs from monopolising the back end resources of the website.

As described in this article about the how the playground is implemented, goroutines that call time.Sleep() are put to sleep. The playground back end waits until all other goroutines are blocked (what would otherwise be a deadlock), and then wakes the goroutine with the shortest time out.

In your program, you have two goroutines: the main one, and one that calls time.Sleep. Since the main goroutine never blocks, the time.Sleep call will never return. The program continues until it exceeds the CPU time allocated to it and is then terminated.




回答3:


The Go Memory Model does not guarantee that the value written to x in the goroutine will ever be observed by the main program. A similarly erroneous program is given as an example in the section on go routine destruction. The Go Memory Model also specifically calls out busy waiting without synchronization as an incorrect idiom in this section.

You need to do some kind of synchronization in the goroutine in order to guarantee that x=1 happens before one of the iterations of the for loop in main.

Here is a version of the program that is guaranteed to work as intended.

http://play.golang.org/p/s3t5_-Q73W

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!")
}

The Go Memory Model guarantees that the line marked with // 1 happens before the line marked with // 2. As a result, the for loop is guaranteed to terminate before its second iteration.



来源:https://stackoverflow.com/questions/20584078/why-does-this-program-terminate-on-my-system-but-not-on-playground

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!