-2

Normal should be constant output

test1
test2
........

But only test1 output, the program hung up, there is no response The assignment of the pointer is the most basic operation, this should be thread-safe to meet the period But this test has not been able to

type Point struct {
    X int
    Y int
}

func main() {
    var p *Point = nil
    test := true
    go func() {
        for test {
            if tmp := p; tmp == nil {
                p = &Point{}
            }
        }
    }()
    go func() {
        for test {
            if tmp := p; tmp != nil {
                p = nil
            }
        }
    }()

    n := 0
    for test {
        n++
        fmt.Printf("testing%v....\r\n",n)
        time.Sleep(1000 * time.Millisecond)
    }

    fmt.Printf("test fail")
}

code: https://play.golang.org/p/-NTq-2iyX5W

if change pointer to int, this is good

func main() {
    var p int = 0
    test := true
    go func() {
        for test {
            if tmp := p; tmp == 0 {
                p = 1
            }
        }
    }()
    go func() {
        for test {
            if tmp := p; tmp != 0 {
                p = 0
            }
        }
    }()

    n := 0
    for test {
        n++
        fmt.Printf("testing%v....\r\n",n)
        time.Sleep(1000 * time.Millisecond)
    }

    fmt.Printf("test fail")
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
san yue
  • 11
  • 1
  • 3
    Your code is racy thus undefined. You _must_ _not_ write to the same variable concurrently. No arguing. – Volker Dec 22 '17 at 11:26
  • When using concurrency, always run tests with race detector (`go test -race`), because you have potential concurrent assignments to the same pointer, and that's bad. This is exactly why golang has things like `select`, channels and the `sync` package containing useful ditties like `sync.Mutex`. Also: `var p *Point = nil` can be shortened to `var p *Point` – Elias Van Ootegem Dec 22 '17 at 13:37
  • thank you . I now know how to deal with this problem. The consequences of such behavior are not clear at present. The entire application is suspended, there is no response, which is not conducive to find the problem. – san yue Dec 23 '17 at 09:39
  • You have 2 busy loops in your code. That’s going to cause problems regardless of race conditions. – JimB Dec 24 '17 at 13:55

1 Answers1

1

The issue is not just that there's a race, but something gets screwed with scheduling when there is a race. The following code has some of the options which will make this code produce the desired output (it's commented). So you either:

  1. add a lock which will fix the race conditions [the correct way]

OR

  1. add a small sleep to each of the racing routines - race continues to be there

This code

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

type Point struct {
    X int
    Y int
}

var lock sync.Mutex

func main() {
    // runtime.GOMAXPROCS(4)
    fmt.Println("Max # of parallel processes = ", MaxParallelism())

    var p *Point = nil
    test := true
    go func() {
        for test {
            // lock.Lock()
            if tmp := p; tmp == nil {
                p = &Point{}
            }
            // lock.Unlock()
            // time.Sleep(1 * time.Nanosecond)

        }
    }()
    go func() {
        for test {
            // lock.Lock()
            if tmp := p; tmp != nil {
                p = nil
            }
            // lock.Unlock()
            // time.Sleep(1 * time.Nanosecond)
        }
    }()

    n := 0
    for test {
        n++
        fmt.Printf("testing%v....\r\n", n)
        time.Sleep(1000 * time.Millisecond)
    }

    fmt.Printf("test fail")
}

func MaxParallelism() int {
    maxProcs := runtime.GOMAXPROCS(0)
    numCPU := runtime.NumCPU()
    if maxProcs < numCPU {
        return maxProcs
    }
    return numCPU
}

Output (on my machine. Please note # of goroutines should be equal or less than the # of virtual processesors for possible parallel computing):

go run main.go 
Max # of parallel processes =  4
testing1....

Inspite of the fact that there are 4 virtual processors the issue seems to be that main never gets scheduled after the first sleep. Apparently when there's a race condition this is somehow inexplicably (atleast for me) rearing it's ugly head. Another observation is that if we reduce one of the two goroutines and also go on to modify the p variable in main's loop, then it works. All this seems to give an impression that the behaviour of the runtime processing is unpredictable when there are race conditions.

Ravi R
  • 1,692
  • 11
  • 16
  • thanks .Your understanding is very good, I now know how to deal with this problem. What I want to say is that the consequences of such behavior are unpredictable at this time if there is competition. However, the entire application is suspended, with no response, which is not good for handling the problem. – san yue Dec 23 '17 at 09:26
  • time.Sleep just solve the probability of error, and can not solve the problem. locker is a viable option – san yue Dec 23 '17 at 09:41
  • Yes, that's why I mention locking is the correct approach (as also implied in @Volker comments). The above code also serves to demonstrate the perils of not using proper synchronization primitives. – Ravi R Dec 23 '17 at 10:21