CSDN问答

电脑版
提示:原网页已由神马搜索转码, 内容由ask.csdn.net提供.

sync / atomic.once.go中的两个原子样式代码是否必要?

已采纳

The code in sync/atomic.once.go is :

func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 1 { //A
//if o.done == 1 {
return
}
// Slow-path.
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
f()
atomic.CompareAndSwapUint32(&o.done, 0, 1) //B
//o.done = 1
}
}

I don't think the two 'atomic-style' code A,B above is necessary or useful. I think the lock is enough, and it could be ok if A,B are not atomic style. I must miss something, please be kind to tell me the purpose of the code A,B. Thank you.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • dqqfuth6736dqqfuth67368年前

    The originalis correct. The reason is that the Go Memory Modelsays, that without synchronization (if o.done == 1) the changes to o.done might not be observed at all.

    点赞 评论复制链接分享
提交

相关推荐

  • 回答 1已采纳The code in sync/atomic.once.go is : func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 1 { //A //if o.done == 1 { return } // Slow-path. o.m.Lock() defer o.m.Unlock() if o.done == 0 { f() atomic.CompareAndSwapUint32(&o.done, 0, 1) //B //o.done = 1 } } I don't think the two 'atomic-style' code A,B above is necessary or useful. I think the lock is enough, and it could be ok if A,B are not atomic style. I must miss something, please be kind to tell me the purpose of the code A,B. Thank you.
  • 回答 1已采纳Golang's atomic package provides function func LoadUint32(addr *uint32) (val uint32). I looked into the assembly implementation: TEXT ·LoadUint32(SB),NOSPLIT,$0-12 MOVQ addr+0(FP), AX MOVL 0(AX), AX MOVL AX, val+8(FP) RET which basically load the value from the memory address and return it. I'm wondering if we have a uint32 pointer(addr) x, what is the difference between calling atomic.LoadUint32(x) and directly access it using *x?
  • 回答 1已采纳As the title says. basically what I'm wondering is that will the atomic.StoreInt32 also lock read operation while it's writing? Another relative question:, is atomic.StoreUint64(&procRate, procCount) equivalent to atomic.StoreUint64(&procRate, atomic.LoadUint64(&procCount))? Thanks in advance.
  • 回答 1已采纳Today I came across a post asking about this question. At the end of the main function in src/runtime/proc.go there is a seemingly useless infinite for loop. Why is it there? source code link if atomic.Load(&panicking) != 0 { gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1) } exit(0) for { var x *int32 *x = 0 }
  • 回答 1已采纳Go implements the sync.Once as such: type Once struct { m Mutex done uint32 } func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 1 { return } // Slow-path. o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(&o.done, 1) f() } } I'm trying to understand the need for the mutex here, what would be the issue with implementing it as this ? func (o *Once) Do(f func()) { if atomic.CompareAndSwapUInt32(&o.done, 0, 1) { f() } }
  • 回答 1已采纳Here are the piece of code to test the mutual access of write and read of a struct B using atomic.Value, but I've got some error indicating invalid pointer access. So what should I do? And what is the idiomatic of doing this? type A struct { numMap map[string]int } type B struct { numMap map[string]*A } var store atomic.Value var chanA chan bool = make(chan bool, 100) var chanB chan bool = make(chan bool, 100) var b *B =& amp;B{} func fetchB() { for i := 0; i& lt; 10000; i++ { c := store.Load().(B) for k, v := range c.numMap { fmt.Println(k, v) for k2, v2 := range v.numMap { fmt.Println(k2, v2) } } } chanA& lt;- true } func writeB() { for i := 0; i& lt; 10000; i++ { //b := store.Load().(B) a := new(A) a.numMap = make(map[string]int) a.numMap["AMap"] = i b.numMap = make(map[string]*A) b.numMap["str"] = a b.numMap["strA"] = a delete(b.numMap, "str") delete(b.numMap["strA"].numMap, "AMap") store.Store(b) } chanB& lt;- true } func main() { store.Store(*b) for i := 0; i& lt; 100; i++ { go writeB() go fetchB() } for i := 0; i& lt; 100; i++ {& lt;-chanA& lt;-chanB } } I'm sorry I've missed something in the first post of the question. If I comment b := store.Load().(B) the error raises, and it is gone if i leave it visible. So why would this happen? the error I've got is something like this: panic: sync/atomic: store of inconsistently typed value into Value goroutine 5 [running]: sync/atomic.(*Value).Store(0x597310, 0x4b7f40, 0x597198) /usr/local/go/src/sync/atomic/value.go:76 +0x1e9 main.writeB() /home/bzhang/devCode/common/src/go/src/audience_service/test.go:47 +0x2cc created by main.main /home/bzhang/devCode/common/src/go/src/audience_service/test.go:54 +0x71 goroutine 1 [chan receive]: main.main() /home/bzhang/devCode/common/src/go/src/audience_service/test.go:59 +0xf3 goroutine 6 [runnable]: main.fetchB() /home/bzhang/devCode/common/src/go/src/audience_service/test.go:23 created by main.main /home/bzhang/devCode/common/src/go/src/audience_service/test.go:55 +0x89 goroutine 7 [runnable]: main.writeB() /home/bzhang/devCode/common/src/go/src/audience_service/test.go:36 created by main.main /home/bzhang/devCode/common/src/go/src/audience_service/test.go:54 +0x71 goroutine 8 [runnable]: main.fetchB() /home/bzhang/devCode/common/src/go/src/audience_service/test.go:23 created by main.main /home/bzhang/devCode/common/src/go/src/audience_service/test.go:55 +0x89 goroutine 9 [runnable]: main.writeB() /home/bzhang/devCode/common/src/go/src/audience_service/test.go:36 created by main.main /home/bzhang/devCode/common/src/go/src/audience_service/test.go:54 +0x7
  • 回答 2已采纳Calling atomic.AddInt64 on field of a struct panics invalid memory address or nil pointer dereference, but not when we re-arrange fields order; why? Using this type: type CountHandler struct { c *RequestContext count int64 } And calling atomic.AddInt64(&countHandler.count, 1) (field c is nil at this point) panics. But not when we rewrite it as: type CountHandler struct { count int64 c *RequestContext } Error goes away. I guess it should be so, because Go keeps data in memory in a sequential manner and reaching a nil value breaks this sequence (of bytes); yet I wonder why is that so again because a pointer should have a fixed size nil or other value. This is Go x86 1.4.2 on Windows& amp; complete error message is: 2015/02/23 12:56:44 http: panic serving [::1]:51886: runtime error: invalid memory address or nil pointer dereference goroutine 5 [running]: net/http.func·011() c:/go/src/net/http/server.go:1130 +0xa8 sync/atomic.AddUint64(0x731144, 0x1, 0x0, 0x0, 0x263168) c:/go/src/sync/atomic/asm_386.s:118 +0xc main.(*CountHandler).ServeHTTP(0x731140, 0x263180, 0x122f6380, 0x122f62a0) C:/Workshop/Devox/Workshop-Go/src/geoho/web/app/app.go:62 +0x42 github.com/julienschmidt/httprouter.func·001(0x263180, 0x122f6380, 0x122f62a0, 0x0, 0x0, 0x0) C:/Workshop/Devox/Workshop-Go/src/github.com/julienschmidt/httprouter/router.go:232 +0x4c github.com/julienschmidt/httprouter.(*Router).ServeHTTP(0x122d5d20, 0x263180, 0x122f6380, 0x122f62a0) C:/Workshop/Devox/Workshop-Go/src/github.com/julienschmidt/httprouter/router.go:298 +0x141 net/http.serverHandler.ServeHTTP(0x122d2280, 0x263180, 0x122f6380, 0x122f62a0) c:/go/src/net/http/server.go:1703 +0x145 net/http.(*conn).serve(0x122e01e0) c:/go/src/net/http/server.go:1204 +0x9d8 created by net/http.(*Server).Serve c:/go/src/net/http/server.go:1751 +0x2ce Whole source code is (this code is wrong, I was just about studying alice): package main import ( "fmt" "github.com/julienschmidt/httprouter" "github.com/justinas/alice" "net/http" "os" "sync/atomic" ) // play with alice func main() { c1 := alice.New(Counter, Texter).Then(nil) router := httprouter.New() router.Handler("GET", "/", c1) router.GET("/kill", kill) http.ListenAndServe(":27007", router) } func kill(rw http.ResponseWriter, rq *http.Request, pl httprouter.Params) { os.Exit(0) } var ch CountHandler // constructors: func Counter(h http.Handler) http.Handler { return& amp;ch } func Texter(h http.Handler) http.Handler { var t TextHandler switch x := h.(type) { case *CountHandler: t.c = x.c t.text = fmt.Sprintf("called so far %d", atomic.LoadInt64(&x.count)) } return& amp;t } // handlers: type RequestContext struct { val int } type CountHandler struct { c *RequestContext count int64 } func (c *CountHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { atomic.AddInt64(&c.count, 1) } type TextHandler struct { c *RequestContext text string } func (t *TextHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { rw.Write([]byte(t.text)) }
  • 回答 1已采纳I write a piece of code to record the num of request. package main import ( "log" "net/http" "runtime" "sync/atomic" ) var count int32 = 0 func test(w http.ResponseWriter, r *http.Request) { count = atomic.LoadInt32(&count) atomic.AddInt32(&count, 1) log.Println("count:", count) } func main() { runtime.GOMAXPROCS(runtime.NumCPU() - 1) http.HandleFunc("/", test) http.ListenAndServe(":8080", nil) } I have considered the condition of concurrency, so I use the atomic pacakge. I test the code via the apache ab tool ab -c 400 -n 1000 http://localhost:8080/ the result is correct: result However, someone said he got the 1004 or other number on his computer, I have tested many times of the code, but the result is correct on my computer, is there wrong with my way? I am new to go, Thanks in advance.
  • 回答 1已采纳This code is simplified and describes my problem. It seems that atomic.StoreInt32 not work but I'm not sure why. package main import ( "fmt" "sync/atomic" ) type slave struct { failed int32 } func NewSlave() slave { return slave{0} } func (worker slave) Fail() { atomic.StoreInt32(&worker.failed, 1) // Here's the problem. } func (worker slave) IsFailed() bool { failed := atomic.LoadInt32(&worker.failed) == 1 return failed } func (worker slave) FailureReset() { atomic.StoreInt32(&worker.failed, 0) } func main() { s := NewSlave() fmt.Println(s.IsFailed()) s.Fail() fmt.Println(s.IsFailed()) s.FailureReset() fmt.Println(s.IsFailed()) } ->output: false 0 false 0 false 0 ->tested on: recolic@RECOLICPC ~/tmp> go version go version go1.9.2 linux/amd64 recolic@RECOLICPC ~/tmp> uname -a Linux RECOLICPC 4.13.12-1-ARCH #1 SMP PREEMPT Wed Nov 8 11:54:06 CET 2017 x86_64 GNU/Linux I've read: usage golang atomic LoadInt32/StoreInt32 (64)
  • 回答 1已采纳Is calling the Wait() method of sync.Cond safe when according to the documentation, it performs an Unlock() first? Assume we are checking for a condition to be met: func sample() { cond =& amp;sync.Cond{L:& amp;sync.Mutex{}} // accessible by other parts of program go func() { cond.L.Lock() for !condition() { cond.Wait() } // do stuff ... cond.L.Unlock() }() go func() { cond.L.Lock() mutation() cond.L.Unlock() cond.Signal() }() } And: func condition() bool { // assuming someSharedState is a more complex state than just a bool return someSharedState } func mutation() { // assuming someSharedState is a more complex state than just a bool // (A) state mutation on someSharedState } Since Wait() performs an Unlock, should (A) has a locking of it's own? Or being atomic?
  • 渣渣酱Z的博客Go语言中可以使用sync包的Mutex类型来实现互斥锁。 例: // 开启多个gorourtine执行add()操作,会导致两个goroutine读取到相同的x导致最终结果偏小 var x = 0 var wg sync.WaitGroup func add() { defer wg.Done()...
  • 七八月份的太阳的博客在sync.Once中我们通过查看源码看到过有使用atomic来实现一个Once只执行一次的操作,我们今天就来着重看一下关于原子操作的atomic sync.Once :https://blog.csdn.net/weixin_40165163/article/details/90246434 ...
  • 胖达喵的博客package main import ( "fmt" "reflect" "sync" "time" ) type A struct{ name string ... fmt.Printf("结构体a的name值:%v\n",a.name) fmt.Printf("结构体a的age值:%v\n",a.age) ...var once sync.Once
  • _ Echo_的博客前言 在我们开发过程中经常会使用到单例模式这一经典的设计...要实现一个单例模式,我们会很快就想到了在一个结构体中放置一个flag字段用于标记当前的函数是否被执行过,举个????: type SingletonPattern struct {
  • 七八月份的太阳的博客Sync.Once 结构: type Once struct { m Mutex done uint32 } 从结构中我们就可以猜出其实现线程安全是通过Mutex来做到的 源码: func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 1 ...
  • 惜暮的博客最近一个项目中某个对象需要持有一个统计对象,并且需要能够原子的更新这个统计对象(并发读写场景下),避免data race。为了避免对象的copy, 肯定是要持有这个统计对象的指针了。 此外,这个统计对象其实是统计的模型...
  • 恋喵大鲤鱼的博客1.简介 sync.Once表示只执行一次函数。要做到这点,就需要两点: ...sync/atomic" ) // Once is an object that will perform exactly one action. type Once struct { m ...
  • wuqin_curry的博客转型做go大概一个多月了吧,工作中也是边写边学,最近也是在极客时间学习一些go相关课程,现学现用,源码在我 github 上:https://github.com/wuqinqiang/Go_Concurrency 是什么 引用官方描述的一段话,Once is a ...
  • 我只要一发的博客Go语言中的sync包中提供了一个针对只执行一次场景的解决方案–sync.Once。 sync.Once只有一个Do方法,其签名如下: func (o *Once) Do(f func()) {} 备注:如果要执行的函数f需要传递参数就需要搭配闭包来使用。 ...
  • Sunshine-松的博客哈喽,大家好,我是asong,这是我并发编程系列的第二篇文章. 上一篇我们一起分析了atomic包,今天我们一起来看一看sync/once的使用与实现.什么是sync.onceGo语言标...