第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Go 中使用 sync.Atomic 包防止競爭條件

在 Go 中使用 sync.Atomic 包防止競爭條件

Go
紫衣仙女 2022-10-24 10:19:35
我在 Go 中實現(xiàn)了以下計數(shù)器,我想同時使用它。我正在使用 atomic 包來存儲狀態(tài),但不確定是否會遇到任何競爭條件。例如,我是否還需要添加一個額外的互斥鎖以防止增量低于零,或者原子操作是否提供足夠的安全性?謝謝!type Counter struct {    counter  uint64    finished uint32    sync.Mutex}// Inc increments the counter by onefunc (c *Counter) Inc() error {    if c.isFinished() {        return fmt.Errorf("counter is finished")    }    atomic.AddUint64(&c.counter, 1)    return nil}// Dec decrements the counter by one, but prevents the counter from going to zerofunc (c *Counter) Dec() {    // prevent overflow    if !c.isZero() {        atomic.AddUint64(&c.counter, ^uint64(0))    }}// Cancel sets the finished flag, and sets counter to zerofunc (c *Counter) Cancel() {    if !c.isFinished() {        atomic.StoreUint32(&c.finished, 1)        atomic.StoreUint64(&c.counter, 0)    }}// isFinished returns true if finishedfunc (c *Counter) isFinished() bool {    return atomic.LoadUint32(&c.finished) == uint32(1)}// isZero returns true if counter is zerofunc (c *Counter) isZero() bool {    return atomic.LoadUint64(&c.counter) == uint64(0)}更新:通過使用-race標(biāo)志運行下面的代碼,我能夠檢測到我確實需要包含互斥鎖。var counter *Counter = &Counter{}func main() {    wg := sync.WaitGroup{}    numberOfLoops := 10    wg.Add(numberOfLoops)    for i := 0; i < numberOfLoops; i++ {        go incrementor(&wg)    }    wg.Wait()    fmt.Println("Final Counter:", counter.counter)}func incrementor(wg *sync.WaitGroup) {    rand.Seed(time.Now().UnixNano())    for i := 0; i < 20; i++ {        counter.Inc()        time.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)    }    wg.Done()    counter.Cancel()}
查看完整描述

2 回答

?
瀟瀟雨雨

TA貢獻(xiàn)1833條經(jīng)驗 獲得超4個贊

您不需要額外的互斥鎖,您的主要功能是在counter.counter不使用原子負(fù)載的情況下讀取,而您的incrementor調(diào)用wg.Done()before counter.Cancel(),因此您會獲得競爭條件。


通過在競爭條件解決wg.Done()后移動:counter.Cancel()


func main() {

    wg := sync.WaitGroup{}


    numberOfLoops := 10

    wg.Add(numberOfLoops)


    for i := 0; i < numberOfLoops; i++ {

        go incrementor(&wg)

    }


    wg.Wait()

    fmt.Println("Final Counter:", counter.counter)

}


func incrementor(wg *sync.WaitGroup) {

    rand.Seed(time.Now().UnixNano())

    for i := 0; i < 20; i++ {

        counter.Inc()

        time.Sleep(time.Duration(rand.Intn(3)) * time.Millisecond)

    }

    counter.Cancel()

    wg.Done()

}


查看完整回答
反對 回復(fù) 2022-10-24
?
Helenr

TA貢獻(xiàn)1780條經(jīng)驗 獲得超4個贊

為了避免“可被比賽檢測器檢測到”的比賽:

正如@caveman 回答的那樣,您遇到的問題與wg.Done() / wg.Wait()指令排序中的問題有關(guān),并且您不使用 anatomic.Load()來訪問counter.counter.


對于這種競爭條件,您的方法是“安全的”。


為了避免比賽,如“不要為計數(shù)器達(dá)到不連貫的狀態(tài)”:

你確實有一個問題,(*)因為你的方法運行了幾個連續(xù)的指令來檢查和更新對象(例如 : if condition { update_fields }),并且你沒有同步機(jī)制來檢查condition應(yīng)用時是否仍然正確update_fields。


通過將您的incrementor功能更改為:


func incrementor(wg *sync.WaitGroup) {

    for i := 0; i < 20000; i++ {

        counter.Inc()

    }

    counter.Cancel()

    wg.Done()

}

并多次運行您的程序,您應(yīng)該能夠看到“Final Counter:”并不總是以 0(操場)結(jié)尾。


這是如何發(fā)生這種情況的說明:


假設(shè) goroutine 1 執(zhí)行counter.Cancel()

而 goroutine 2 執(zhí)行counter.Inc()

可能會發(fā)生以下執(zhí)行順序:


   goroutine 1                                 goroutine 2


                                            1. if c.isFinished() {

                                                   return fmt.Errorf("counter is finished")

                                               }

2. if !c.isFinished() {                         

3.     atomic.StoreUint32(&c.finished, 1)       

4.     atomic.StoreUint64(&c.counter, 0)        

   }                                            

                                            5. atomic.AddUint64(&c.counter, 1)

                                            6. return nil

中的c.isFinished()指令.Inc()可能在執(zhí)行之前發(fā)生, .Cancel()

并且atomic.AddUint64(&c.counter, 1)可能在將計數(shù)器重置為零之后發(fā)生。 .Cancel()

為了避免這種競爭,您需要選擇一種同步inspect + update指令的方式。


一種常見的方法是使用互斥鎖:


type Counter struct {

    counter  uint64

    finished uint32

    m        sync.Mutex

}


// Inc increments the counter by one

func (c *Counter) Inc() error {

    c.m.Lock()

    defer c.m.Unlock()


    if c.finished != 0 {

        return fmt.Errorf("counter is finished")

    }


    c.counter++

    return nil

}


// Dec decrements the counter by one, but prevents the counter from going to zero

func (c *Counter) Dec() {

    c.m.Lock()

    defer c.m.Unlock()


    // prevent overflow

    if c.counter > 0 {

        c.counter--

    }

}


// Cancel sets the finished flag, and sets counter to zero

func (c *Counter) Cancel() {

    c.m.Lock()

    defer c.m.Unlock()


    if c.finished == 0 {

        c.finished = 1

        c.counter = 0

    }

}



查看完整回答
反對 回復(fù) 2022-10-24
  • 2 回答
  • 0 關(guān)注
  • 117 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號