Search code examples
gowebservermutexgoroutine

sync.Mutex or http.HandleFunc not working


I am using the textbook: "The Go Programming Language" and in it they show how to make a webserver using Go.

Following the code they give, I made a webserver:

package main

import (
    "fmt"
    "log"
    "net/http"
    "sync"
)

var mu sync.Mutex
var count int

func main() {
    http.HandleFunc("/", handler)
    http.HandleFunc("/count", counter)
    log.Fatal(http.ListenAndServe("localhost:8080", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    count++
    mu.Unlock()
    fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}

func counter(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    fmt.Fprintf(w, "Count %d\n", count)
    mu.Unlock()
}

Afterwards I wanted to test my knowledge with goroutines so I made a program that will call the server endpoint: "/rest" 1000 times.

Then I call the endpoint: "/count" which is suppose to return the amount of times the previous endpoint was called.

send.go

package main

import (
    "fmt"
    "net/http"
    "os"
    "strconv"
    "io/ioutil"
)

func main() {
    times, _ := strconv.Atoi(os.Args[1])
    
    for i := 0; i < times; i++ {
        go call()
    }

    response, err := http.Get("http://localhost:8080/count")
    if err != nil {
        fmt.Println("ERROR ", err)
    }
    
    text, _ := ioutil.ReadAll(response.Body)
    fmt.Println(string(text))
    response.Body.Close()
}

func call() {
    _, _= http.Get("http://localhost:8080/rest")
}

The problem is this: the /count endpoint returns a number less than 1000. Please tell me what I am doing wrong, or if there is I'm misunderstanding about how sync.Mutex or http.HandleFunc() works.


Solution

  • The mutex only ensures that no two goroutines will write/read count at the same time, however it does not control the order in which those goroutines are executed.

    That means that there is nothing in your code that ensures that all of the go call() are finished before http.Get(".../count") is executed.

    If you want to execute http.Get(".../count") only after all of the go call() are finished, then you can do that by using a sync.WaitGroup.