2017-01-08 47 views
3

在指定GOARCH=amd64選項並在64位操作系統上運行時,golang中指針值的大小是32位還是64位?是對golang中的原子指針值的讀取或寫入操作?

如果它是64位大小,是一個全局指針值8字節對齊內存,以便該指針值的讀取或寫入操作是原子執行的?

例如,在下面的代碼中,當讀取goroutine讀取指針時,是否有可能全局指針p只是部分更新?

var p *int 

void main() { 
    i := 1 
    p = &i 
    go func() { 
     fmt.Println(*p) 
    }() 
} 

我有關的情況是,只有一個寫,但多次讀取,在全球指針值和指針的舊值讀數並不重要。提前致謝!

+0

不可以。唯一的原子操作是通過'sync/atomic'。您始終需要同步讀取和寫入。 – JimB

+0

[另請參閱](http://stackoverflow.com/q/41406501/720999)。 – kostix

回答

3

唯一確保原子化的東西是sync.atomic中的操作。

所以,如果你想確定你需要一個鎖,例如sync.Mutex或使用其中一個原子基元。我不推薦使用原子基元,因爲你必須在使用指針的地方使用它們,而且它們很難正確使用。

使用互斥OK Go的風格 - 你可以定義一個函數來鎖定很容易,比如像返回當前指針

import "sync" 

var secretPointer *int 
var pointerLock sync.Mutex 

func CurrentPointer() *int { 
    pointerLock.Lock() 
    defer pointerLock.Unlock() 
    return secretPointer 
} 

func SetPointer(p *int) { 
    pointerLock.Lock() 
    secretPointer = p 
    pointerLock.Unlock() 
} 

這些函數返回指針的一個拷貝給他們的客戶這將即使主指針被改變也保持不變。這可能會或可能不會被接受,具體取決於時間對您的要求有多重要。它應該足以避免任何未定義的行爲 - 垃圾收集器將確保指針始終保持有效,即使指向的內存不再被程序使用。

另一種方法是隻執行一次去例行程序的指針訪問,並使用通道來執行例行事務處理的命令。這會被認爲是更習慣性的,但可能不適合你的應用程序。

Here is an example顯示如何使用atomic.SetPointer。由於使用不安全的指數,這相當醜陋。然而,不安全的.Pointer將編譯轉換爲空白,因此運行時成本很小。

import (
    "fmt" 
    "sync/atomic" 
    "unsafe" 
) 

type Struct struct { 
    p unsafe.Pointer // some pointer 
} 

func main() { 
    data := 1 

    info := Struct{p: unsafe.Pointer(&data)} 

    fmt.Printf("info is %d\n", *(*int)(info.p)) 

    otherData := 2 

    atomic.StorePointer(&info.p, unsafe.Pointer(&otherData)) 

    fmt.Printf("info is %d\n", *(*int)(info.p)) 

} 
+0

我同意使用unsafe.Pointer相當難看。你必須定義一個unsafe.Pointer類型的變量,而不是定義一個指向具體類型的指針,例如'var p * Struct =&Struct {}'。 – ncubrian