How to make Golang Packages thread-safe

Golang Thread-safe Tutorial

Concurrency is such a foundational capability of the Go language that it is effortless to write code that leverages multiple goroutines, sometimes without even knowing.

For example, if you’ve ever used the net/http package to create a web service, you’ve used goroutines.

To handle incoming HTTP traffic, the HTTP Server will generate a goroutine for every connection and one per request with HTTP/2. These goroutines are transparent to the user; you wouldn’t know they were goroutines unless you’ve read the documentation.

This ease of use makes creating multi-goroutine applications simple, it also makes it easy to create data race conditions.

Data Race with Golang

A data race is when at least two threads or, in this case, goroutines try to access the same data. For example, one goroutine tries to read data while another writes data. This scenario will cause a Golang application to panic and crash.

To explain better, let’s say we created a simple Global within our application that holds a counter.

var counter int

And an HTTP handler to increment this counter.

Because each HTTP request initiates its goroutine, there is a high chance that two goroutines (HTTP requests) will try to increment the counter simultaneously. This will result in a panic condition.

What’s unfortunate about this example is that this data race may not be found with basic testing. Data races are all about timing, two requests have to increment the counter simultaneously.

This example bug can get past standard testing.

Enable Data Race Detection with Golang

However, Golang has a simple way to detect data race conditions. While executing tests, it is possible to turn on data race detection using the --race flag.