# Data lost? I have more than 300000 data left. Why? [concurrent problems]

Blogger introduction:

- I'm Li Fan. I like to contribute to the simple book every day. The pseudonym of reading comprehension: March_ Liu Chao . Focus on the Go Web backend, and have learned about Python, Java, algorithms, front-end and other fields. The Milky way WeChat official account is waiting for your attention, Penguin Group Number (798829931). Come on in the future~

# background

Everyone is familiar with Go language and is good at concurrent operation, but for me who initially stepped into Xiaobai, I encountered a problem today, that is, data loss!!

# Original problem

Today, I wrote a small program to try concurrent operations. For example, we use 10 goroutines to accumulate a variable concurrently. Each goroutine is responsible for 100000 operations. We expect that the final result must be 10 coroutines * 100000 accumulations = 1 million data. Let's see whether the code description is correct.

## program

```package main

import (
"fmt"
"sync"
)

func main() {
var count = 0
// Use WaitGroup to wait for 10 goroutine s to complete
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
// Execute the variable count 10 times plus 1
for j := 0; j < 100000; j++ {
count ++
}
}()
}
// Wait for 10 goroutine s to complete
wg.Wait()
fmt.Println(count)
}
```

## result

We can clearly see that only more than 300000 data do not meet our expectations. Why?

# Analyze problems

First, we analyze the following code

```go func() {
defer wg.Done()
// Execute the variable count 10 times plus 1
for j := 0; j < 100000; j++ {
count ++
}
}()
```

There are no other problems. Let's take a closer look at the operation in the for loop. There is only one count + + operation. If you have a little basic language syntax, you should understand how the + + operation operates at the bottom of the computer. At least three steps are required. For example, take the current value of the variable count, add 1 to this value, and save the result in count (see the details below), This is obviously not an atomic operation. Since atoms must be indivisible, there may be a problem of concurrency.

count operation in assembly language

```MOVQ  "".COUNT(SB), AX
LEAQ  1(AX), CX
MOVQ  CX, "".count(SB)
```

For example, 10 goroutine s read the value of count as 9000 at the same time, then add 1 according to their own logic, and the value becomes 9001, and then write the result back to the count variable. However, in fact, the total number we should increase at this time should be 10, but only 1 is increased here, and many counts are "swallowed". This is a common error in accessing shared data concurrently.

Maybe some experienced problems can be solved easily, but what if some problems have no experience?

## How to find similar problems

At this time, Go provides a tool to detect whether there is a problem with concurrent access to shared resources: race detector, which can automatically find whether there is a data race problem in the program.

Use test tools:

```go run -race main.go
```

For example:

When compiling, test ing or run ning Go code, adding the race parameter may find concurrency problems. From the above results, we can clearly see which line has concurrency problems, and we can clearly solve them. Of course, this tool enables the application of race to be deployed online, which still affects the performance.

# solve the problem

The above program problem is that the shared resources are count variables and the critical area is count + +. As long as the lock is obtained in front of the critical area and released when leaving the critical area, the problem of data race can be solved perfectly.

```package main

import (
"fmt"
"sync"
)

func main() {
// Mutex protection calculator
var mu sync.Mutex

// Counter value
var count = 0

// Use WaitGroup to wait for 10 goroutine s to complete
var wg sync.WaitGroup

for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
// Execute the variable count 10 times plus 1
for j := 0; j < 100000; j++ {
mu.Lock()
count ++
mu.Unlock()
}
}()
}

// Wait for 10 goroutine s to complete
wg.Wait()
fmt.Println(count)
}
```

## result

It can be found that the data race runs normally, and there are no warnings. The problem is solved perfectly.