Go語(yǔ)言 sync.Mutex 源碼分析

go 語(yǔ)言以并發(fā)作為其特性之一晰奖,并發(fā)必然會(huì)帶來(lái)對(duì)于資源的競(jìng)爭(zhēng),這時(shí)候我們就需要使用 go 提供的 sync.Mutex 這把互斥鎖來(lái)保證臨界資源的訪問(wèn)互斥努溃。

既然經(jīng)常會(huì)用這把鎖拆融,那么了解一下其內(nèi)部實(shí)現(xiàn),就能了解這把鎖適用什么場(chǎng)景捻爷,特性如何了。

打開源碼份企,我們先看一下mutex.go文件的描述也榄。

// Mutex fairness.
//
// Mutex can be in 2 modes of operations: normal and starvation.
// In normal mode waiters are queued in FIFO order, but a woken up waiter
// does not own the mutex and competes with new arriving goroutines over
// the ownership. New arriving goroutines have an advantage -- they are
// already running on CPU and there can be lots of them, so a woken up
// waiter has good chances of losing. In such case it is queued at front
// of the wait queue. If a waiter fails to acquire the mutex for more than 1ms,
// it switches mutex to the starvation mode.
//
// In starvation mode ownership of the mutex is directly handed off from
// the unlocking goroutine to the waiter at the front of the queue.
// New arriving goroutines don't try to acquire the mutex even if it appears
// to be unlocked, and don't try to spin. Instead they queue themselves at
// the tail of the wait queue.
//
// If a waiter receives ownership of the mutex and sees that either
// (1) it is the last waiter in the queue, or (2) it waited for less than 1 ms,
// it switches mutex back to normal operation mode.
//
// Normal mode has considerably better performance as a goroutine can acquire
// a mutex several times in a row even if there are blocked waiters.
// Starvation mode is important to prevent pathological cases of tail latency.

//------------------------------------------------------------------------------------------------------------------------------------
// 互斥公平鎖 .
// 鎖有兩種模式,【正常模式】和【饑餓模式】
// 在正常模式下鎖有等待鎖的goroutine都會(huì)進(jìn)入一個(gè)先進(jìn)先出的隊(duì)列(輪流被喚醒)司志,但是被
//喚醒的goroutine不會(huì)直接獲得鎖,而是要跟新到來(lái)的gorotine競(jìng)爭(zhēng)甜紫。
//新來(lái)的goroutine有個(gè)一個(gè)優(yōu)勢(shì) -- 他們已近CPU上運(yùn)行降宅,并且數(shù)量眾多,
//所以剛被喚醒的goroutine大概率獲取不到鎖.在這樣的情況下囚霸,被喚醒的goroutine會(huì)被
//隊(duì)列頭部腰根。如果一個(gè)goroutine等待超過(guò)1ms(寫死的)沒有獲取到鎖,互斥鎖將進(jìn)入饑餓模式拓型。
//
//在饑餓模式中额嘿,解鎖的goroutine會(huì)將鎖直接交付給等待隊(duì)里最前面的goroutine.
//新來(lái)的goroutine 不會(huì)嘗試獲取鎖(即使鎖在空閑狀態(tài)),也不會(huì)進(jìn)行自旋吨述,
//他們只是加入到等待隊(duì)列尾部.
//
//如果一個(gè)goroutine 獲取到鎖岩睁,他會(huì)判斷
//1 . 他是否是位于等待隊(duì)列末尾
//2 . 他等待是否超過(guò)1ms
// 以上只有有一個(gè)成立,將把互斥鎖切換至正常模式
//
// 正常模式 :具有較好的性能揣云,即使存在許多阻塞者,goroutine也也會(huì)嘗試幾次獲取鎖冰啃。
// 饑餓模式 :對(duì)于防止尾部延遲是非常重要的邓夕。

sync.Mutex

// A Mutex 是一個(gè)互斥鎖
// 0 值代碼表未加鎖轉(zhuǎn)態(tài)
//
//互斥鎖在第一次被使用后不能被復(fù)制.
type Mutex struct {
    state int32
    sema  uint32
}

const (
    mutexLocked = 1 << iota // mutex is locked state第1位
    mutexWoken //state第2位
    mutexStarving //state第3位
    mutexWaiterShift = iota

    starvationThresholdNs = 1e6
)


stage

這個(gè)字段會(huì)同時(shí)被多個(gè)goroutine公用(使用atomic來(lái)保證原子性),第1個(gè)bit 表示已加鎖阎毅。第2個(gè)bit 表示某個(gè)goroutine被喚醒焚刚,嘗試獲取鎖,第3個(gè)bit表示這把鎖是否是饑餓狀態(tài)扇调。

[1][1][1] : 第一個(gè)[1] 表示鎖狀態(tài)矿咕,第二個(gè)[1]表示是否有喚醒,第三個(gè)[1]表示是否是饑餓模式
·001普通模式 狼钮,無(wú)喚醒碳柱, 鎖 ,010 普通模式熬芜, 有喚醒 莲镣,無(wú)鎖狀態(tài),,101 饑餓模式 涎拉,無(wú)喚醒 瑞侮,鎖

sema

用來(lái)喚醒 goroutine 所用的信號(hào)量。

LOCK

在看代碼之前鼓拧,我們需要有一個(gè)概念:每個(gè) goroutine 也有自己的狀態(tài)半火,存在局部變量里面(也就是函數(shù)棧里面),goroutine 有可能是新到的季俩、被喚醒的钮糖、正常的、饑餓的种玛。

func (m *Mutex) Lock() {
    // 如果鎖是空閑狀態(tài)藐鹤,直接獲取鎖 通過(guò) atomic.CompareAndSwapInt32 保證原子性
    if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
        if race.Enabled {
            race.Acquire(unsafe.Pointer(m))
        }
        return
    }
    //用來(lái)保存 goroutine 等待時(shí)間
    var waitStartTime int64
    // 用來(lái)存當(dāng)前goroutine是否饑餓
    starving := false
    // 用來(lái)存當(dāng)前goroutine是否已喚醒
    awoke := false
    // 用來(lái)存當(dāng)前goroutine的循環(huán)次數(shù)
    iter := 0
    // 復(fù)制一下當(dāng)前鎖的狀態(tài)
    old := m.state
    //自旋起來(lái)
    for {
        // Don't spin in starvation mode, ownership is handed off to waiter
        //[翻譯] 在饑餓模式下就不要自旋了瓤檐,因?yàn)殒i會(huì)直接被交付
        // so we won't be able to acquire the mutex anyway.
        //[翻譯]  所以自旋也獲取不到鎖

         // 第一個(gè)條件是state已被鎖,但是不是饑餓狀態(tài)娱节。如果時(shí)饑餓狀態(tài)挠蛉,自旋時(shí)沒有用的,鎖的擁有權(quán)直接交給了等待隊(duì)列的第一個(gè)肄满。
         // 第二個(gè)條件是還可以自旋谴古,多核、壓力不大并且在一定次數(shù)內(nèi)可以自旋稠歉,
         // 如果滿足這兩個(gè)條件掰担,不斷自旋來(lái)等待鎖被釋放、或者進(jìn)入饑餓狀態(tài)怒炸、或者不能再自旋带饱。
        // [偽代碼]:if isLocked() and isNotStarving() and canSpin()
        if old&(mutexLocked|mutexStarving) == mutexLocked && runtime_canSpin(iter) {
            // Active spinning makes sense.
            //[翻譯]  主動(dòng)自旋是有意義的
            // Try to set mutexWoken flag to inform Unlock
            //[翻譯] 嘗試修改喚醒標(biāo)志
            // to not wake other blocked goroutines.
            //[翻譯] 這樣就可以不喚醒其他goroutines

            // 自旋的過(guò)程中如果發(fā)現(xiàn)state還沒有設(shè)置woken標(biāo)識(shí),則設(shè)置它的woken標(biāo)識(shí)阅羹, 并標(biāo)記自己為被喚醒勺疼。
            //  atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken)  這段代碼來(lái)修改 mutex stage 第2位 設(shè)置有喚醒標(biāo)識(shí)。這樣就不會(huì)去喚醒其他的goroutine了
            if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
                atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
                awoke = true
            }
            //進(jìn)行自旋
            runtime_doSpin()
            //循環(huán)迭代計(jì)數(shù)
            iter++
           //更新鎖的狀態(tài) 捏鱼,因?yàn)樵谶@段時(shí)間里鎖的狀態(tài)可能被其他goroutine修改了
            old = m.state
            continue
        }

        //到了這一步执庐,state的狀態(tài)可能是
        //1. 未加鎖 ,普通模式
        //2. 未加鎖导梆,饑餓模式
        //3. 已加鎖轨淌,饑餓模式
        //4. 已加鎖,普通模式 (可能做上面執(zhí)行時(shí)看尼,鎖被其他goroutine 獲取了)
        
        //獲取鎖的最新狀態(tài)递鹉,這個(gè)字段用來(lái)存儲(chǔ)希望設(shè)置鎖的狀態(tài)
        new := old
        // Don't try to acquire starving mutex, new arriving goroutines must queue.
         //[翻譯]不要饑餓模式下獲取鎖,新來(lái)的去排隊(duì)

       // [偽代碼]:if isNotStarving() 狡忙,也就是說(shuō)是饑餓狀態(tài)時(shí)不獲取鎖
        if old&mutexStarving == 0 {
            //new 設(shè)置為獲取鎖狀態(tài)
            new |= mutexLocked
        }
        //如果是鎖狀態(tài)梳虽,或者是饑餓狀態(tài),就設(shè)置等待隊(duì)列+1 灾茁,(此時(shí)就是等位 +1)
        if old&(mutexLocked|mutexStarving) != 0 {
            new += 1 << mutexWaiterShift
        }

               
        // The current goroutine switches mutex to starvation mode.
        //[翻譯] 當(dāng)前goroutine 將所切換至饑餓模式
        // But if the mutex is currently unlocked, don't do the switch.
        //[翻譯]但是如果鎖的狀態(tài)是unlocked 就不要切換窜觉。
        // Unlock expects that starving mutex has waiters, which will not  be true in this case.
        //[翻譯] unlock 期望一個(gè)饑餓模式的gorutine時(shí),這個(gè)例子就不成立了(也就說(shuō)如果有其他的goroutine將鎖切換成饑餓模式)
        
        //[偽代碼] isStarving and isLock
        if starving && old&mutexLocked != 0 {
            new |= mutexStarving
        }
        //如果當(dāng)前goroutine 是喚醒狀態(tài)北专,那么我要resest這個(gè)狀態(tài)
        //因?yàn)間oroutine要么是拿到鎖了禀挫,要么是進(jìn)入sleep了
        if awoke {
            // The goroutine has been woken from sleep,
            //[翻譯]goroutine 已近被喚醒了。
            // so we need to reset the flag in either case.
            //[翻譯]所以我們要切換狀態(tài)了
            if new&mutexWoken == 0 {
                throw("sync: inconsistent mutex state")
            }
            //設(shè)置成非喚醒狀態(tài)
            new &^= mutexWoken
        }

        // 通過(guò)CAS來(lái)嘗試設(shè)置鎖的狀態(tài)
        // 這里可能是設(shè)置鎖拓颓,也有可能是只設(shè)置為饑餓狀態(tài)和等待數(shù)量
        if atomic.CompareAndSwapInt32(&m.state, old, new) {
           
            // 如果old state的狀態(tài)是未被鎖狀態(tài)语婴,并且鎖不處于饑餓狀態(tài),
            // 那么當(dāng)前goroutine已經(jīng)獲取了鎖的擁有權(quán),返回
            if old&(mutexLocked|mutexStarving) == 0 {
                break // locked the mutex with CAS
            }
            // If we were already waiting before, queue at the front of the queue.
            //[翻譯] 如果我們已經(jīng)在排隊(duì)了,就排在隊(duì)伍的最前面砰左。
            queueLifo := waitStartTime != 0
            if waitStartTime == 0 {
                //計(jì)算等待時(shí)間
                waitStartTime = runtime_nanotime()
            }
            // 既然未能獲取到鎖匿醒, 那么就使用sleep原語(yǔ)阻塞本goroutine
            // 如果是新來(lái)的goroutine,queueLifo=false, 加入到等待隊(duì)列的尾部,耐心等待
            // 如果是喚醒的goroutine, queueLifo=true, 加入到等待隊(duì)列的頭部
            runtime_SemacquireMutex(&m.sema, queueLifo)
          
            //如果當(dāng)前是饑餓狀態(tài)缠导,并且等待超過(guò)1ms
            starving = starving || runtime_nanotime()-waitStartTime > starvationThresholdNs
          // 得到當(dāng)前的鎖狀態(tài)
            old = m.state
            if old&mutexStarving != 0 {
                // If this goroutine was woken and mutex is in starvation mode,
                //[翻譯] 如果這個(gè)goroutine喚醒廉羔,并且鎖是饑餓模式
                // ownership was handed off to us but mutex is in somewhat
                //[翻譯] 鎖會(huì)直接傳遞給我們
                // inconsistent state: mutexLocked is not set and we are still
                //[翻譯] 如果鎖處于不一致狀態(tài),那么會(huì)出現(xiàn)問(wèn)題
                // accounted as waiter. Fix that.
                if old&(mutexLocked|mutexWoken) != 0 || old>>mutexWaiterShift == 0 {
                    throw("sync: inconsistent mutex state")
                }
                // 當(dāng)前的goroutine獲得了鎖僻造,那么就把等待隊(duì)列-1
                delta := int32(mutexLocked - 1<<mutexWaiterShift)
                //如果是最后一個(gè)等待者憋他,就退出饑餓模式
                if !starving || old>>mutexWaiterShift == 1 {
                    // Exit starvation mode.
                    //[翻譯] 退出饑餓模式
                    // Critical to do it here and consider wait time.
                    //[翻譯]重要的是要在這里做,并考慮等待時(shí)間髓削。
                    // Starvation mode is so inefficient, that two goroutines can go lock-step infinitely 
                    //[翻譯]饑餓模式非常低效竹挡,兩個(gè)goroutine一旦切換到饑餓模式,就會(huì)無(wú)限地執(zhí)行鎖步立膛。
                    delta -= mutexStarving
                }
                //加鎖
                atomic.AddInt32(&m.state, delta)
                break
            }
           // 如果鎖不是饑餓模式揪罕,就把當(dāng)前的goroutine設(shè)為被喚醒
           // 并且重置iter(重置spin)
            awoke = true
            iter = 0
        } else {
            // 如果CAS不成功,也就是說(shuō)沒能成功獲得鎖旧巾,鎖被別的goroutine獲得了或者鎖一直沒被釋放
            // 那么就更新狀態(tài)耸序,重新開始循環(huán)嘗試拿鎖
            old = m.state
        }
    }

    if race.Enabled {
        race.Acquire(unsafe.Pointer(m))
    }
}

UNLOCK

接下來(lái)我們來(lái)看看 Unlock 的實(shí)現(xiàn),對(duì)于 Unlock 來(lái)說(shuō)鲁猩,有兩個(gè)比較關(guān)鍵的特性:
如果說(shuō)鎖不是處于 locked 狀態(tài),那么對(duì)鎖執(zhí)行 Unlock 會(huì)導(dǎo)致 panic罢坝;
鎖和 goroutine 沒有對(duì)應(yīng)關(guān)系廓握,所以我們完全可以在 goroutine 1 中獲取到鎖,然后在 goroutine 2 中調(diào)用 Unlock 來(lái)釋放鎖(這是什么騷操作`夷稹)

// Unlock unlocks m.
// [翻譯] 解鎖
// It is a run-time error if m is not locked on entry to Unlock.
//[翻譯] 如果沒有l(wèi)ocked 執(zhí)行 unlock 會(huì)有一個(gè)run-time error
// A locked Mutex is not associated with a particular goroutine.
//[翻譯] 一個(gè)被鎖的互斥對(duì)象與一個(gè)特定的goroutine沒有關(guān)聯(lián)隙券。
// It is allowed for one goroutine to lock a Mutex and then
//[翻譯] 允許其他的goroutine進(jìn)行解鎖
// arrange for another goroutine to unlock it.
func (m *Mutex) Unlock() {
    if race.Enabled {
        _ = m.state
        race.Release(unsafe.Pointer(m))
    }

    // Fast path: drop lock bit.

      
    //解鎖
    new := atomic.AddInt32(&m.state, -mutexLocked)
    if (new+mutexLocked)&mutexLocked == 0 {
        throw("sync: unlock of unlocked mutex")
    }
        
    //解鎖成功,并且不是解鎖狀態(tài)
    if new&mutexStarving == 0 {
        //復(fù)制鎖狀態(tài)
        old := new
        for {
            // If there are no waiters or a goroutine has already
            // been woken or grabbed the lock, no need to wake anyone.
            // In starvation mode ownership is directly handed off from unlocking
            // goroutine to the next waiter. We are not part of this chain,
            // since we did not observe mutexStarving when we unlocked the mutex above.
            // So get off the way.
            // [翻譯] 如果沒有沒有等待著闹司,或者沒有喚醒的goroutine娱仔,不用喚醒任何人。
            //如果沒有其他的goroutine 加鎖游桩。
            //在饑餓模式下鎖會(huì)被直接傳遞牲迫,但是我們這里不關(guān)注饑餓模式下的設(shè)置,
            if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken|mutexStarving) != 0 {
                return
            }

            // Grab the right to wake someone.
            // 走到這一步的時(shí)候借卧,說(shuō)明鎖目前還是空閑狀態(tài)盹憎,并且沒有g(shù)oroutine被喚醒且隊(duì)列中有g(shù)oroutine等待拿鎖
            // 那么我們就要把鎖的狀態(tài)設(shè)置為被喚醒,等待隊(duì)列-1
            new = (old - 1<<mutexWaiterShift) | mutexWoken
            // 如果狀態(tài)設(shè)置成功了铐刘,我們就通過(guò)信號(hào)量去喚醒goroutine
            if atomic.CompareAndSwapInt32(&m.state, old, new) {
                runtime_Semrelease(&m.sema, false)
                return
            }
            // 循環(huán)結(jié)束的時(shí)候陪每,更新一下狀態(tài),因?yàn)橛锌赡茉趫?zhí)行的過(guò)程中,狀態(tài)被修改了(比如被Lock改為了饑餓狀態(tài))
            old = m.state
        }
    } else {
        // 饑餓模式下檩禾, 直接將鎖的擁有權(quán)傳給等待隊(duì)列中的第一個(gè).
        // 注意此時(shí)state的mutexLocked還沒有加鎖挂签,喚醒的goroutine會(huì)設(shè)置它。
        // 在此期間盼产,如果有新的goroutine來(lái)請(qǐng)求鎖饵婆, 因?yàn)閙utex處于饑餓狀態(tài), mutex還是被認(rèn)為處于鎖狀態(tài)辆飘,
        // 新來(lái)的goroutine不會(huì)把鎖搶過(guò)去.
        runtime_Semrelease(&m.sema, true)
    }
}

結(jié)語(yǔ)

鎖和解鎖的代碼只有這么簡(jiǎn)單的幾行啦辐,但是其中的原來(lái)和設(shè)計(jì)的巧妙點(diǎn)缺非常多,從這個(gè)里我們可以看出蜈项,系統(tǒng)設(shè)計(jì)的好壞跟代碼多少無(wú)關(guān)芹关,系統(tǒng)內(nèi)涵的設(shè)計(jì)跟代碼設(shè)計(jì)也無(wú)關(guān),真的大師一定是大道至簡(jiǎn)紧卒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侥衬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子跑芳,更是在濱河造成了極大的恐慌轴总,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件博个,死亡現(xiàn)場(chǎng)離奇詭異怀樟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)盆佣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門往堡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人共耍,你說(shuō)我怎么就攤上這事虑灰。” “怎么了痹兜?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵穆咐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我字旭,道長(zhǎng)对湃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任谐算,我火速辦了婚禮熟尉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘洲脂。我一直安慰自己斤儿,他們只是感情好剧包,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著往果,像睡著了一般疆液。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陕贮,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天堕油,我揣著相機(jī)與錄音,去河邊找鬼肮之。 笑死掉缺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的戈擒。 我是一名探鬼主播眶明,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼筐高!你這毒婦竟也來(lái)了搜囱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柑土,失蹤者是張志新(化名)和其女友劉穎蜀肘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稽屏,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扮宠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狐榔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涵卵。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖荒叼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情典鸡,我是刑警寧澤被廓,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站萝玷,受9級(jí)特大地震影響嫁乘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜球碉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一蜓斧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧睁冬,春花似錦挎春、人聲如沸看疙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)能庆。三九已至,卻和暖如春脚线,著一層夾襖步出監(jiān)牢的瞬間搁胆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工邮绿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渠旁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓船逮,卻偏偏與公主長(zhǎng)得像顾腊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子傻唾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • go語(yǔ)言以并發(fā)作為其特性之一投慈,并發(fā)必然會(huì)帶來(lái)對(duì)于資源的競(jìng)爭(zhēng),這時(shí)候我們就需要使用go提供的sync.Mutex這把...
    PureWhiteWu閱讀 538評(píng)論 1 3
  • 針對(duì)Golang 1.9的sync.Mutex進(jìn)行分析冠骄,與Golang 1.10基本一樣除了將panic改為了th...
    freelang閱讀 4,497評(píng)論 5 11
  • 本文基于 go1.11 版本伪煤。 Mutex 使用 在深入源碼之前,要先搞清楚一點(diǎn)凛辣,對(duì) Golang 中互斥鎖 sy...
    LLLeon閱讀 1,598評(píng)論 0 4
  • sync.mutex 源代碼分析 [TOC] 針對(duì) Golang 1.10.3 的 sync.Mutex 進(jìn)行分析...
    CoffeeRabbit閱讀 625評(píng)論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月抱既,有人笑有人哭,有人歡樂有人憂愁扁誓,有人驚喜有人失落防泵,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,536評(píng)論 28 53