Добрый день.
Представим такой код:
type A struct{}
func (a *A) method1() {
// some code
}
var pointerToA *A
func init() {
pointerToA = &A{}
}
func goroutine1() {
// ....
pointerToA.method1()
// ....
}
func goroutine2() {
// ....
pointerToA = pointerToAnotherA
// ....
}
Есть ли какие либо гарантии на то что внутри
goroutine1 указатель
pointerToA всегда будет указывать либо на старый адрес либо на новый, но никогда не случится так что в
pointerToA находится часть от старого адреса и часть от нового? Интересует случай архитектуры AMD64.
В
AMD64 Architecture Programmers Manual Volumes 2, в разделе 7.3.2 Access Atomicity написано следующее:
Cacheable, naturally-aligned single loads or stores of up to a quadword are atomic on any processor
model, as are misaligned loads or stores of less than a quadword that are contained entirely within a
naturally-aligned quadword. Misaligned load or store accesses typically incur a small latency penalty.
Model-specific relaxations of this quadword atomicity boundary, with respect to this latency penalty,
may be found in a given processor's Software Optimization Guide.
Misaligned accesses can be subject to interleaved accesses from other processors or cache-coherent
devices which can result in unintended behavior. Atomicity for misaligned accesses can be achieved
where necessary by using the XCHG instruction or any suitable LOCK-prefixed instruction.
Что говорит нам (как я понимаю) что если адрес который мы читаем/пишем выровнен (в данном случае на 8 байт) то чтение/запись атомарны. Остаётся понять есть ли какие либо гарантии от компилятора Go на выравнивание указателя. Единственное мето в спецификации Go где говорится про выравниевание это
Size and alignment guarantees:
The following minimal alignment properties are guaranteed:
For a variable x of any type: unsafe.Alignof(x) is at least 1.
For a variable x of struct type: unsafe.Alignof(x) is the largest of all the values unsafe.Alignof(x.f) for each field f of x, but at least 1.
For a variable x of array type: unsafe.Alignof(x) is the same as the alignment of a variable of the array's element type.
A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.
И вот тут самое непонятное. Каких то конкретных гарантий на адреса указателей нет. Можно вызвать функцию
unsafe.Alignof(*A) и получить то что мне нужно. Но будет ли результат Alignof(*A) для AMD64 всегда постоянным?
Как один из вариантов решения проблемы использовать
atomic.Pointer[A] вместо
*A, но судя по тестам он медленее в два раза. Поэтому хочется понять можно ли тут как то улучшить ситуацию.
Надеюсь понятно изложил суть вопроса.
Всем заранее спасибо за ответы.