A case of the original Golang mutex

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.
package mainimport ("fmt""runtime""sync")type Counter struct {mu sync.Mutexx  int64}func (c *Counter) Inc() {c.mu.Lock()defer c.mu.Unlock()c.x++}func main() {runtime.GOMAXPROCS(runtime.NumCPU())c := Counter{}var wait sync.WaitGroupwait.Add(4)for k := 4; k > 0; k-- {go func() {for i := 2500000; i > 0; i-- {c.Inc()}wait.Done()}()}wait.Wait()fmt.Println(c.x)}

The above is a more common example, the following is the collation of some explanations

+++++++++++++++++++++++++++++++++++++++

The Golang Sync package implements two types of lock mutexes (mutexes) and Rwmutex (read and write locks), where Rwmutex is implemented based on mutexes, and read-only locks are implemented using similar functions as reference counters.

Type Mutex

Func (M *mutex) Lock ()

Func (M *mutex) Unlock ()

Type Rwmutex

Func (rw *rwmutex) Lock ()

Func (rw *rwmutex) Rlock ()

Func (rw *rwmutex) rlocker () Locker

Func (rw *rwmutex) Runlock ()

Func (rw *rwmutex) Unlock ()

Where the mutex is a mutex, lock () lock, Unlock () Unlock, use lock () lock, you can not lock it again, until it is unlocked with Unlock (), it can be locked again. For read-write uncertainty scenarios, where there is no obvious difference between read and write times, and only one read or write is allowed, the lock leaf is called a global lock.

Func (M *mutex) Unlock () is used to unlock m, which can cause a run error if not locked before using Unlock ().

A locked mutex is not associated with a particular goroutine, so it can be locked with one goroutine and then unlocked with another goroutine.

Example of normal operation:

package main    import (      "fmt"      "sync"  )    func main() {      var l *sync.Mutex      l = new(sync.Mutex)      l.Lock()      defer l.Unlock()      fmt.Println("1")  }  结果输出:1   

When unlock () is used before lock (), an error is raised

package main    import (      "fmt"      "sync"  )    func main() {      var l *sync.Mutex      l = new(sync.Mutex)      l.Unlock()      fmt.Println("1")      l.Lock()  }  运行结果: panic: sync: unlock of unlocked mutex  

When the lock is locked again before unlocking, the deadlock state

package main    import (      "fmt"      "sync"  )    func main() {      var l *sync.Mutex      l = new(sync.Mutex)      l.Lock()      fmt.Println("1")      l.Lock()  }  运行结果:  1        fatal error: all goroutines are asleep - deadlock!  

Rwmutex is a read-write lock that can add multiple read locks or a write lock, which is often used to read far more than the number of writes.

Func (rw *rwmutex) lock () write lock, if there are additional read and write locks before the write lock is added, lock blocks until the lock is available, and to ensure that the lock is finally available, the blocked lock call excludes the new reader from the acquired lock, that is, the write lock permission is higher than the read lock. Write lock is preferred when there is write lock
The func (rw *rwmutex) Unlock () write lock unlocks, which causes a run-time error if no write lock is made.

package main    import (      "fmt"      "sync"  )    func main() {      var l *sync.RWMutex      l = new(sync.RWMutex)      l.Unlock()      fmt.Println("1")      l.Lock()  }  运行结果:panic: sync: unlock of unlocked mutex  

Func (rw *rwmutex) rlock () read lock, when there is a write lock, cannot load read lock, when there is only read lock or no lock, can load read lock, read lock can load multiple, so for "read more write less" scenario

The func (rw *rwmutex) runlock () read lock unlocks, Runlock revokes a single rlock call, and it has no effect on other readers that exist simultaneously. If RW is not locked for reading, calling Runlock raises a run-time error (Note: This is not the case in the go1.3 version, for example).

package main    import (      "fmt"      "sync"  )    func main() {      var l *sync.RWMutex      l = new(sync.RWMutex)      l.RUnlock()    //1个RUnLock      fmt.Println("1")      l.RLock()                }    运行结果:1  但是程序中先尝试 解锁读锁,然后才加读锁,但是没有报错,并且能够正常输出.  

Analysis: go1.3 version of the cause of this situation analysis, read the source code can be very clear to get results

func (rw *RWMutex) RUnlock() {      if raceenabled {          _ = rw.w.state          raceReleaseMerge(unsafe.Pointer(&rw.writerSem))          raceDisable()      }<span style="color:#FF0000;">      if atomic.AddInt32(&rw.readerCount, -1) < 0 { //readercounter初始值为0,调用RUnLock之后变为-1,继续往下执行          // A writer is pending.          if atomic.AddInt32(&rw.readerWait, -1) == 0 { //此时readerwaiter变为1,1-1之后变为0,可以继续以后的操作.</span>              // The last reader unblocks the writer.              runtime_Semrelease(&rw.writerSem)          }      }      if raceenabled {          raceEnable()      }  }  

When the Runlock is more than Rlock, it will error and enter the deadlock. Examples are as follows:

package main    import (      "fmt"      "sync"  )    type s struct {      readerCount int32  }    func main() {      l := new(sync.RWMutex)      l.RUnlock()      l.RUnlock()        //此处出现死锁      fmt.Println("1")      l.RLock()  }  运行结果:  1        fatal error: all goroutines are asleep - deadlock!  

Summarize:

Therefore, in the go1.3 version, the operation allows Runlock to be earlier than the Rlock one, and can only be earlier than 1 (note: Although the code is allowed, but strongly deprecated), and after the Rlock must be used to lock to continue to use.

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.