This prints 0.
But when I add empty fmt.Println() in for loop its prints non zero value.
Any ideas why?
GOMAXPROCS=1 ./foo
0
package main
import (
"log"
"os"
"time"
)
func main() {
var i uint64
t := time.AfterFunc(time.Second*1, func() {
log.Println(i)
os.Exit(0)
})
defer t.Stop()
for {
i++
}
}
You have a data race: you access the same variable from multiple goroutines without synchronization. The results are undefined. Use proper synchronization.
It's true that you don't launch goroutines in your code, but quoting from time.AfterFunc():
AfterFunc waits for the duration to elapse and then calls f in its own goroutine.
So you have the main goroutine incrementing (writing) the variable i, and you'll have another goroutine executing the function you pass to time.AfterFunc() which will read i.
Example to use synchronization:
var (
mu sync.Mutex
i uint64
)
t := time.AfterFunc(time.Second*1, func() {
mu.Lock()
log.Println(i)
mu.Unlock()
os.Exit(0)
})
defer t.Stop()
for {
mu.Lock()
i++
mu.Unlock()
}
Related
Is there any way to make goroutine execute one after another ( one by one) if it was the same function?
I didn't mean to use goroutine firstly. However, "os/exec" function in TCP will cause the tcp forced to stop. Thus I use goroutine to avoid crashing. But I still want them to execute by order, instead of concurrently. Here is my code.
func handleTCP(conn net.Conn) {
defer conn.Close()
fmt.Println("handle TCP function")
for {
wg := new(sync.WaitGroup)
wg.Add(1)
go func() {
cmdArgs := []string{temp_str, test_press, gh, "sample.csv"}
cmd := exec.Command("calib.exe", cmdArgs...)
wg.Done()
}()
}
}
You can use locks to limit access to a resource to one thread at a time as follows
i := 1
iLock = &sync.Mutex{}
for {
go func() {
iLock.Lock()
fmt.Printf("Value of i: %d\n", i)
iLock.Unlock()
}
}
More examples here
Not sure what you are using the WaitGroup for. If it is to achieve the sequentiality you desire, then it can be removed.
Try to put the lock into function, it makes theirs execution sequential. But remember about wg.Done() must be under defer at first line of the function.
Something like this:
var mu sync.Mutex
func handleTCP(conn net.Conn) {
defer conn.Close()
fmt.Println("handle TCP function")
for {
wg := new(sync.WaitGroup)
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
defer mu.UnLock()
cmdArgs := []string{temp_str, test_press, gh, "sample.csv"}
cmd := exec.Command("calib.exe", cmdArgs...)
}()
}
}
I'm new to Go so please excuse my ignorance. I'm attempting to iterate through a bunch of wordlists line by line indefinitely with goroutines. But when trying to do so, it does not iterate or stops half way through. How would I go about this in the proper manner without breaking the flow?
package main
import (
"bufio"
"fmt"
"os"
)
var file, _ = os.Open("wordlist.txt")
func start() {
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func main(){
for t := 0; t < 150; t++ {
go start()
fmt.Scanln()
}
}
Thank you!
You declare file as a global variable. Sharing read/write file state amongst multiple goroutines is a data race and will give you undefined results.
Most likely, reads start where the last read from any of the goroutines left off. If that's end-of-file, it likely continues to be end-of-file. But, since the results are undefined, that's not guaranteed. Your erratic results are due to undefined behavior.
Here's a revised version of your program that declares a local file variable and uses a sync.Waitgroup to synchronize the completion of all the go start() goroutines and the main goroutine. The program checks for errors.
package main
import (
"bufio"
"fmt"
"os"
"sync"
)
func start(filename string, wg *sync.WaitGroup, t int) {
defer wg.Done()
file, err := os.Open(filename)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
lines := 0
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines++
}
if err := scanner.Err(); err != nil {
fmt.Println(err)
return
}
fmt.Println(t, lines)
}
func main() {
wg := &sync.WaitGroup{}
filename := "wordlist.txt"
for t := 0; t < 150; t++ {
wg.Add(1)
go start(filename, wg, t)
}
wg.Wait()
}
So, I have this (just an example):
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(5 * time.Second)
for {
select {
case <-ticker.C:
fmt.Println("hello")
}
}
}
This is an infinite loop, and I want it that way. In the real code it loops every 1 hour.
But, what if I want to call a func to make it stop looping? Is this possible?
Something like:
func stop() {
//this will stop the main function from looping
}
I know I could do something like:
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(5 * time.Second)
done := make(chan bool)
go func() {
for {
select {
case <-done:
fmt.Println("done")
ticker.Stop()
return
case <-ticker.C:
fmt.Println("hello")
}
}
}()
time.Sleep(10 * time.Second)
done <- true
}
But that would be stoping the function from a predefined time frame(in this case 10 seconds), which is not what I want and also this is all within the same function, I need to make a call from outside the main function.
Is this possible somehow?
Here:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func stop(ch chan<- struct{}) {
select {
// Triggers after 7 seconds
case <-time.After(7 * time.Second):
ch <- struct{}{}
}
}
func signalStop(ch chan<- struct{}) {
// Use a buffered channel (size = 1)
sig := make(chan os.Signal, 1)
// Use SIGINT signal i.e., <kill -SIGINT XXXX> or <Control+C>
signal.Notify(sig, syscall.SIGINT)
select {
// Capture the SIGINT signal
case <-sig:
// Close the channel
close(ch)
}
}
func main() {
ticker := time.NewTicker(1 * time.Second)
done := make(chan struct{})
// Spawn a goroutine with the done channel
go signalStop(done)
for {
select {
case <-ticker.C:
fmt.Println("Hello!")
case <-done:
// When stop signals, stop the ticker and return
ticker.Stop()
fmt.Println("Bye, bye!")
return
}
}
}
I've commented the relevant parts of the code so that you understand what I'm trying to do.
In the below code:
package main
import "fmt"
func main() {
for i := 0; i <= 9; i++ {
go func() {
fmt.Println(i)
}()
}
}
Output:
code$
code$ go install github.com/myhub/cs61a
code$ bin/cs61a
code$
Above program does not provide any output.
1) Is their a data race for single memory location i among 10 go-routines?
2) Why above code does not print value of free variable i?
Is there a data race?
Yes, confirm it by running go run -race example.go. The main goroutine writes i, and the other goroutines read it without any synchronization. See Passing parameters to function closure; Why do these two for loop variations give me different behavior? and Register multiple routes using range for loop slices/map.
Why above code does not print anything?
Because when the main goroutine ends, your program ends as well. It does not wait for other non-main goroutines to finish. See No output from goroutine
Fix
Make a copy of the loop variable, and use that in the closures, and use a sync.WaitGroup to wait for the launched goroutines to end:
var wg sync.WaitGroup
for i := 0; i <= 9; i++ {
i2 := i
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println(i2)
}()
}
wg.Wait()
This will output (try it on the Go Playground):
9
0
2
1
6
5
3
7
8
4
An alternative is to pass i as a parameter to the launched function:
var wg sync.WaitGroup
for i := 0; i <= 9; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(i)
}(i)
}
wg.Wait()
Try this one on the Go Playground.
I have the following for-select structure in code:
go func(runCh chan Caller, shutdownSignal chan bool) {
for {
select {
case request := <-runCh:
go func() {
w.Run(&request)
}()
case <-shutdownSignal:
w.Shutdown()
return
}
}
}(runCh, shutdownCh)
Will I have some problems with this part:
case request := <-runCh:
go func() {
w.Run(&request)
}()
?
If yes, then why?
In other words - does Using goroutines on loop iterator variables part of Common Mistakes also apply to my case and why it does/does not apply here?
No (does not apply here), you have new variable (memory address) on each loop iteration:
case request := <-runCh:
Because this := creates new variable distinct from previous one, proof:
package main
import (
"fmt"
"time"
)
func main() {
runCh := make(chan int, 2)
runCh <- 1
runCh <- 2
for i := 1; i <= 2; i++ {
select {
case request := <-runCh:
go func() {
fmt.Println(request, &request)
time.Sleep(200 * time.Millisecond)
fmt.Println(request, &request)
}()
}
}
time.Sleep(500 * time.Millisecond)
}
Output (the address of request in each loop iteration is different):
1 0xc0000b8000
2 0xc0000b8008
1 0xc0000b8000
2 0xc0000b8008
See: 0xc0000b8000 != 0xc0000b8008