The sync.Mutex type

The sync.Mutex type is the Go implementation of a mutex. Its definition, which can be found in the mutex.go file of the sync directory, is as follows:

// A Mutex is a mutual exclusion lock. 
// The zero value for a Mutex is an unlocked mutex. 
// 
// A Mutex must not be copied after first use. 
type Mutex struct { 
    state int32 
    sema  uint32 
} 

The definition of the sync.Mutex type is nothing extraordinary. All of the interesting work is being done by the sync.Lock() and sync.Unlock() functions that can lock and unlock a sync.Mutex mutex, respectively. Locking a mutex means that nobody else can lock it until it has been released using the sync.Unlock() function.

The mutex.go program, which is going to be presented in five parts, illustrates the use of the sync.Mutex type.

The first code segment of mutex.go follows next:

package main 
 
import ( 
    "fmt" 
    "os" 
    "strconv" 
    "sync" 
    "time" 
) 
 
var ( 
    m  sync.Mutex 
    v1 int 
) 

The second part of mutex.go is shown in the following Go code:

func change(i int) { 
    m.Lock() 
    time.Sleep(time.Second) 
    v1 = v1 + 1 
    if v1%10 == 0 { 
          v1 = v1 - 10*i 
   } 
    m.Unlock() 
} 

The critical section of this function is the Go code between the m.Lock() and m.Unlock() statements.

The third part of mutex.go contains the following Go code:

func read() int { 
    m.Lock() 
    a := v1 
    m.Unlock() 
    return a 
} 

Similarly, the critical section of this function is defined by the m.Lock() and m.Unlock() statements.

The fourth code segment of mutex.go follows next:

func main() { 
    if len(os.Args) != 2 { 
         fmt.Println("Please give me an integer!") 
         return 
    } 
 
    numGR, err := strconv.Atoi(os.Args[1]) 
    if err != nil { 
         fmt.Println(err) 
         return 
    } 
    var waitGroup sync.WaitGroup 

The last part of mutex.go is shown in the following Go code:

fmt.Printf("%d ", read()) 
    for i := 0; i < numGR; i++ { 
         waitGroup.Add(1) 
         go func(i int) { 
               defer waitGroup.Done() 
               change(i) 
               fmt.Printf("-> %d", read()) 
         }(i) 
   } 
 
    waitGroup.Wait() 
    fmt.Printf("-> %d
", read()) 
} 

Executing mutex.go will generate the following output:

$ go run mutex.go 21
0 -> 1-> 2-> 3-> 4-> 5-> 6-> 7-> 8-> 9-> -30-> -29-> -28-> -27-> -26-> -25-> -24-> -23-> -22-> -21-> -210-> -209-> -209
$ go run mutex.go 21
0 -> 1-> 2-> 3-> 4-> 5-> 6-> 7-> 8-> 9-> -130-> -129-> -128-> -127-> -126-> -125-> -124-> -123-> -122-> -121-> -220-> -219-> -219
$ go run mutex.go 21
0 -> 1-> 2-> 3-> 4-> 5-> 6-> 7-> 8-> 9-> -100-> -99-> -98-> -97-> -96-> -95-> -94-> -93-> -92-> -91-> -260-> -259-> -259

If you remove the m.Lock() and m.Unlock() statements from the change() function, the program will generate output similar to the following:

$ go run mutex.go 21
0 -> 1-> 6-> 7-> 5-> -60-> -59-> 9-> 2-> -58-> 3-> -52-> 4-> -57-> 8-> -55-> -90-> -54-> -89-> -53-> -56-> -51-> -89
$ go run mutex.go 21
0 -> 1-> 7-> 8-> 9-> 5-> -99-> 4-> 2-> -97-> -96-> 3-> -98-> -95-> -100-> -93-> -94-> -92-> -91-> -230-> 6-> -229-> -229
$ go run mutex.go 21
0 -> 3-> 7-> 8-> 9-> -120-> -119-> -118-> -117-> 1-> -115-> -114-> -116-> 4-> 6-> -112-> 2-> -111-> 5-> -260-> -113-> -259-> -259

The reason for such a change in the output is that all goroutines are simultaneously changing the shared variable, which is the main reason that the output appears randomly generated.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.182.76