Go Series Tutorial--25. Mutex

Source: Internet
Author: User
Tags mutex
This is a creation in Article, where the information may have evolved or changed. Welcome to the 25th chapter of [Golang Series Tutorial] (HTTPS://STUDYGOLANG.COM/SUBJECT/2). In this tutorial we learn about mutexes. We will also learn how to handle race conditions (Race Condition) through mutexes and [channel] (https://studygolang.com/articles/12402). # # Critical section before learning about mutexes, we need to understand the concept of critical sections (Critical section) in concurrent programming. When the program runs concurrently, multiple [Go threads] (https://studygolang.com/articles/12342) should not have access to the code that modifies the shared resource at the same time. The code that modifies the shared resource is called a critical section. For example, suppose we have a piece of code that adds a variable ' x ' from 1. "' Gox = x + 1 ' If there is only one go association accessing the code snippet above, there is no problem. But when there are multiple concurrent runs, the code goes wrong, so let's see why. For simplicity's sake, let's say we've run two Go routines in front of a line of code. Within the previous line of code, the system executes the program at the following steps (in fact, there are a lot of technical details including registers, as well as how the addition works, but for our series of tutorials, just think only three steps are good): 1. Gets the current value of x 2. Calculate x + 13. Assign the value calculated in step 2 to X if there is only one process to perform the above three steps, there will be no problem. Let's talk about what happens when there are two concurrent threads executing the code. Describes a scenario that can occur when two threads concurrently access the code line ' x = x + 1 '. [One-scenario] (https://raw.githubusercontent.com/studygolang/gctt-images/master/golang-series/cs5.png) We assume that the initial value of ' X ' is 0. And the co-process 1 Gets the initial value of ' X ' and computes ' x + 1 '. The system context switches to coprocessor 2 before the value assigned to ' x ' is calculated in the 1. So, the Association 2 gets the initial value of ' X ' (still 0), and calculates ' x + 1 '. Then the system context is switched back to the co-process 1. Now, the coprocessor 1 assigns the computed value 1 to ' x ', so ' x ' equals 1. Then, the process 2 continues to execute and calculatesThe value (still 1) is copied to ' X ', so ' x ' is equal to 1 after all the threads have finished executing. Now let's consider another scenario that could happen. [Another-scenario] (https://raw.githubusercontent.com/studygolang/gctt-images/master/golang-series/cs-6.png) In the above scenario, the process 1 begins to execute, The end is completed with three steps, so the value of ' X ' equals 1. Next, you start the execution of the coprocessor 2. The current value of ' X ' is equal to 1. When the 2 execution is complete, the value of ' X ' equals 2. So, from these two examples you can see that the final value of ' X ' is 1 or 2, depending on the context switch. This less desirable condition is called a race condition (Race Condition), and the output of its program is determined by the execution order of the association. * * In the above example, a race condition can be avoided if only one go process is allowed to access the critical section at any time. The use of mutexes can achieve this purpose * *. # # Mutexmutex is used to provide a locking mechanism (Locking mechanism) to ensure that only one process is running at a time in the critical section to prevent race conditions. The Mutex can be found within the [sync] (https://golang.org/pkg/sync/) package. [Mutex] (https://tip.golang.org/pkg/sync/#Mutex) defines two methods: [Lock] (https://tip.golang.org/pkg/sync/#Mutex. Lock) and [Unlock] ( https://tip.golang.org/pkg/sync/#Mutex. Unlock). All the code between ' Lock ' and ' Unlock ' can only be executed by a Go association, thus avoiding race conditions. "' Gomutex. Lock () x = x + 1 mutex. Unlock () "" In the above code, ' x = x + 1 ' can only be executed by a Go coprocessor, thus avoiding race conditions. If a Go process already holds a lock, the threads are blocked until the Mutex is unlocked when other threads attempt to acquire the lock. # # programs with race conditions in this section, we'll write a program that contains race conditions, and in the next section, we'll fix the race condition. "' Gopackage maIn import ("FMT" "Sync") var x = 0 Func increment (WG *sync. Waitgroup) {x = x + 1 WG. Done ()}func main () {var w sync. Waitgroup for I: = 0; i < 1000; i++ {w.add (1) Go Increment (&w)} w.wait () fmt. Println ("Final value of X", X)} "in the above program, the ' increment ' function on line 7th adds the value of ' X ' to 1 and calls [Waitgroup] (https://studygolang.com/articles /12512) ' Done ', notifying the function that it has ended. In line 15th of the above procedure, we have generated 1000 ' increment ' co-processes. Each Go process runs concurrently, and because the 8th line attempts to increase the value of ' X ', multiple concurrent threads attempt to access the value of ' X ', and a race condition occurs. Because [playground] (http://play.golang.org) is deterministic, race conditions do not occur in playground, please run the program locally. Run a few more times on your local machine, and you can see that each output is different due to race conditions. Several of the outputs I have encountered have ' final value of x 941 ', ' final value of x 928 ', ' final value of x 922 ' and so on. # # using a mutex in the previous program, we created 1000 Go routines. If each process has an ' x ' plus 1, the final ' x ' expected value should be 1000. In this section, we will use mutexes in our programs to fix race condition issues. "' Gopackage main import (" FMT "" Sync ") var x = 0 Func increment (WG *sync. Waitgroup, M *sync. Mutex) {M.lock () x = x + 1 m.unlock () WG. Done ()}func main () {var w sync. Waitgroup var m sync. Mutex for I: = 0; i < 1000; i++ {W.add (1) go increment (&w, &m)} w.wait () fmt. Println ("Final value of X", X)} "[Run in Playground] (https://play.golang.org/p/VX9dwGhR62) [Mutex] (https://golang.org /pkg/sync/#Mutex) is a struct type, we create a ' Mutex ' type variable ' m ' in line 15th, with a value of zero. In the above procedure, we modified the ' increment ' function to place the ' X ' Code (' x = x + 1 ') between ' m.lock () ' and ' M.unlock () '. Now there is no race condition for this code, because only one process is allowed to execute this code at any moment. If you run the program, it will output: ' Final value of x 1000 ' in line 18th, it is important to pass the address of the Mutex. If the value of the mutex is passed, not the address, then each of the threads will get a copy of the mutex, and the race condition will still occur. # # using channels to process race conditions we can also use channels to process race conditions. See how it's done. "' Gopackage main import (" FMT "" Sync ") var x = 0 Func increment (WG *sync. Waitgroup, CH chan bool) {ch <-true x = x + 1 <-CH WG. Done ()}func main () {var w sync. Waitgroup ch: = Make (chan bool, 1) for I: = 0; i < 1000; i++ {w.add (1) Go increment (&w, ch)} w.wait () fmt. Println ("Final value of X", X)} ' [Run in Playground] (https://play.golang.org/p/M1fPEK9lYz) in the above program, we have created a buffer channel of capacity 1 ( https://studygolang.com/articles/12512), and in the 18th line it will pass in the ' Increment ' Association. The buffered channel is used to ensure that only one of the access increases ' X' The critical section. The specific implementation is to pass ' true ' to the buffer channel before the ' X ' is added (line 8th). Because the buffer channel has a capacity of 1, blocking occurs when any other coprocessor attempts to write to the channel, and the value of the channel is not read until the ' x ' is incremented (line 10th). In fact, this ensures that only one process is allowed to access the critical section. The program also outputs: "Final value of X $" # # Mutex vs Channel by using mutexes and channels, we have solved the problem of race condition. So which one do we choose to use? The answer depends on the problem you want to solve. If the problem you want to solve is more appropriate for a mutex, use a mutex. If you need to use a Mutex, no hesitation. If the problem is more appropriate for the channel, then the channel is used. :) Since the channel is a cool feature of the go language, most go novices use channels when dealing with each concurrency problem. That's not right. Go gives you the option of choosing a Mutex and a channel, and choosing one of them can be right. In general, a channel can be used when the Go process needs to communicate with other co-processes. A Mutex can be used when only one of the threads is allowed to access the critical section. In terms of the problems we've solved above, I prefer to use mutexes because the problem does not require communication between the threads. So the Mutex is a natural choice. My advice is to choose the tools that are specific to the problem, and don't let the problem go to the tools. :) This concludes the tutorial. Have a nice day. * * Previous tutorial-[Select] (https://studygolang.com/articles/12522) * * * Next tutorial-[struct substitution class] (https://studygolang.com/articles/12630) * *

via:https://golangbot.com/mutex/

Author: Nick Coghlan Translator: Noluye proofreading: polaris1119

This article by GCTT original compilation, go language Chinese network honor launches

This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove

2,383 Reads
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.