dongyu7074 2019-04-29 12:48
浏览 122

互斥体的golang实现中是否存在竞争条件-在没有原子函数的情况下读取m.state

In golang if two goroutines read and write a variable without mutex and atomic, that may bring data race condition.

Use command go run --race xxx.go will detect the race point.

While the implementation of Mutex in src/sync/mutex.go use the following code

       func (m *Mutex) Lock() {
   // Fast path: grab unlocked mutex.
   if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
       if race.Enabled {
           race.Acquire(unsafe.Pointer(m))
       }
       return
   }

   var waitStartTime int64
   starving := false
   awoke := false
   iter := 0
   old := m.state     // This line confuse me !!!
       ......

The code old := m.state confuse me, because m.state is read and write by different goroutine.

The following function Test obvious has race condition problem. But if i put it in mutex.go, no race conditon will detect.

# mutex.go
func Test(){
    a := int32(1)
        go func(){
                atomic.CompareAndSwapInt32(&a, 1, 4)
        }()
        _ = a
}

If put it in other package like src/os/exec.go, the conditon race problem will detect.

package main

import(
    "sync"
    "os"
)
func main(){
    sync.Test()        // race condition will not detect
    os.Test()          // race condition will detect
}
  • 写回答

2条回答 默认 最新

  • doulongdan2264 2019-04-29 17:35
    关注

    First of all the golang source always changes so let's make sure we are looking at the same thing. Take release 1.12 at

    https://github.com/golang/go/blob/release-branch.go1.12/src/sync/mutex.go

    as you said the Lock function begins

    func (m *Mutex) Lock() {
        // fast path where it will set the high order bit and return if not locked
        if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
            return
        }
        //reads value to decide on the lower order bits
        for {
            //if statements involving CompareAndSwaps on the lower order bits
        }
    }
    

    What is this CompareAndSwap doing? it looks atomically in that int32 and if it is 0 it swaps it to mutexLocked (which is 1 defined as a const above) and returns true that it swapped it. Then it promptly returns. That is its fast path. The goroutine acquired the lock and now it is running can start running it's protected path.

    If it is 1 (mutexLocked) already, it doesn't swap it and returns false (it didn't swap it).

    Then it reads the state and enters a loop that it does atomic compare and swaps to determine how it should behave.

    What are the possible states? combinations of locked, woken and starving as you see from the const block.

    Now depending on how long the goroutine has been waiting on the waitlist it will get priority on when to check again if the mutex is now free.

    But also observe that only Unlock() can set the mutexLocked bit back to 0. in the Lock() CAS loop the only bits that are set are the starving and woken ones.Yes you can have multiple readers but only one writer at any time, and that writer is the one who is holding the mutex and is executing its protected path until calling Unlock(). Check out this article for more details.

    评论

报告相同问题?

悬赏问题

  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改
  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上