Reputation: 1031
I have a very basic Golang application that creates and runs a HTTP server. The server has 2 endpoints, one to send data and one to receive.
Upon each POST request to the server, parse the incoming data from the body and push it onto a channel. I then have a function that reads from the channel and saves the data to a map.
Upon each GET request to the server, JSON marshal the map and send it to the client.
Each request to the HTTP server runs asynchronously and the worker function writes to the map synchronously in its own goroutine.
Basic pseudo code is as follows:
package main
import (
"net/http"
)
type dataStore map[string]string
func listenHandler(stream chan string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// JSON unmarshal request body
// push data onto stream
stream <- data
}
}
func serveHandler(store *dataStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// JSON marshal data store
// serve to client
}
}
func worker(stream <-chan string) *dataStore {
store := make(dataStore)
go func() {
for data := range stream {
// process and write data to map
}
}()
return &store
}
func main() {
stream := make(chan string)
store := worker(stream)
http.HandleFunc("/listen", listenHandler(stream))
http.HandleFunc("/serve", serveHandler(store))
http.ListenAndServe(":8080", nil)
}
I have tested and ran the application with no problems, however I have been told it has a potential race condition and I am not sure why. Is this true?
Upvotes: 3
Views: 1280
Reputation: 46423
In the code given, you're only synchronizing your writes, not your reads; that means you still might read from the map while you're writing to it, which would be a race condition.
To make it thread-safe, you need to wrap both reads and writes in a concurrency structure - either using channels or a mutex - in order to ensure that only one thread is accessing it at any given time if it is a write operation. Multiple threads can safely read at the same time, as long as no thread is writing to it. RWMutex
provides this functionality explicitly.
Upvotes: 2