-2

I wrote a simple GO program that should start 3 GO routines. However, the GO routines don't start.

Please note that the situation is not identical to the one describer within this post :

Why is my goroutine not executed?

The program should wait for the GO routines to end their execution... Thus, the program should wait forever (since the routines never stop).

package main

import (
    "fmt"
    "net"
    "os"
    "time"
    "sync"
)

func main() {

    wg := sync.WaitGroup{}

    fmt.Print("Starting 3 clients\n")

    for i:=0; i<3; i++ {

        client := func(inName string) {

            fmt.Printf("Client <%s> started\n", inName)

            wg.Add(1)
            conn, err := net.Dial("tcp", ":8000")
            if err != nil {
                fmt.Printf("[%s] Error while connecting to the server: %s", inName, err.Error())
                os.Exit(1)
            }

            n := 0
            sleepDuration, _ := time.ParseDuration("2s")
            for {
                message := fmt.Sprintf("[%s] > message %d\n", inName, n)
                fmt.Printf("%s", message)
                _, err := conn.Write([]byte(message))
                if nil != err {
                    fmt.Sprintf("[%s] Error while writing data to the socket: %s", inName, err.Error())
                    os.Exit(1)
                }
                time.Sleep(sleepDuration)
                n++
            }
        }

        name := fmt.Sprintf("Client%d", i)
        fmt.Printf("Starting client <%s>...\n", name)
        go client(name)
        fmt.Print("Done\n")
    }

    wg.Wait()
}

Result:

Starting 3 clients
Starting client <Client0>...
Done
Starting client <Client1>...
Done
Starting client <Client2>...
Done
Denis Kertios
  • 73
  • 1
  • 5
  • 3
    You **must** call wg.Add(1) from _outside_ of the goroutine. Otherwise wg.Wait() might not (in your case: does not) see the Add(1). – Volker Apr 03 '18 at 08:44
  • 2
    Putting `wg.Add(1)` inside goroutine is a race condition. You don't know whether the those `Add` have been executed when `wg.Wait()` is called. And you forgot to call `Done()` in goroutine. – llllllllll Apr 03 '18 at 08:46
  • All right, I understand. This tool acts as a simple counter. Thanks. – Denis Kertios Apr 03 '18 at 15:09
  • Possible duplicate of [Example for sync.WaitGroup correct?](https://stackoverflow.com/questions/19208725/example-for-sync-waitgroup-correct) – mu is too short Apr 03 '18 at 17:28
  • @DenisKertios is the given answer solved your problem? If it does, you may accept it. – Abdullah Al Maruf - Tuhin Apr 13 '18 at 20:29

1 Answers1

3

As this solution says:

It is important that the wg.Add() happens before the go statement to prevent race conditions. The following would also be correct:

So, you need to take out wg.Add(1) off inside of go routine itself and call it just before starting go routines. Also, call defer wg.Done() at the start of the function, so that, it will decrements the WaitGroup counter by one. Take a look at the code below.

package main

import (
    "fmt"
    "net"
    "os"
    "time"
    "sync"
)

func main() {

    wg := sync.WaitGroup{}

    fmt.Print("Starting 3 clients\n")

    for i:=0; i<3; i++ {

        client := func(inName string) {

            defer wg.Done() // added this line

            fmt.Printf("Client <%s> started\n", inName)

            conn, err := net.Dial("tcp", ":8000")
            if err != nil {
                fmt.Printf("[%s] Error while connecting to the server: %s", inName, err.Error())
                os.Exit(1)
            }

            n := 0
            sleepDuration, _ := time.ParseDuration("2s")
            for {
                message := fmt.Sprintf("[%s] > message %d\n", inName, n)
                fmt.Printf("%s", message)
                _, err := conn.Write([]byte(message))
                if nil != err {
                    fmt.Sprintf("[%s] Error while writing data to the socket: %s", inName, err.Error())
                    os.Exit(1)
                }
                time.Sleep(sleepDuration)
                n++
            }
        }

        name := fmt.Sprintf("Client%d", i)
        fmt.Printf("Starting client <%s>...\n", name)
        wg.Add(1) // moved this line
        go client(name)
        fmt.Print("Done\n")
    }

    wg.Wait()
}