int64的读写操作是否具有原子性质

Posted adream307

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了int64的读写操作是否具有原子性质相关的知识,希望对你有一定的参考价值。

x86-64 机器上,int64 的读写操作是否具有原子性?

假设变量 valint64, 现在有两个线程,线程 writer 只负责向 val 写入数据,线程 reader 只负从 val 读取数据

假设 val 当前值为 0x0102030405060708

writer 线程正在执行写操作,将数据 0x0000111100002222 写入 val

reader 线程正在执行读操作,从 val 读取数据

那么 reader 线程得到的 val 只能是 0x01020304050607080x0000111100002222 还是某个不确定的中间状态?

如果 int64 的读写操作具有原子性,那么 reader 线程得到的只能是 0x01020304050607080x0000111100002222

如果 int64 的读写操作不具有原子性,那么 reader 线程得到可能是中间某个不确定的状态,比如前一半是 writer 正在写入的数据,后一半是旧的数据 0x0000111105060708

测试程序如下:

  1. 写入 val 的值一定是符合奇偶校验的
  2. 开启 10 个线程同时向 val 输入数据
  3. 读线程连续的从 val 读取数据,并检查是否符合奇偶校验
  4. 如果 int64 的读写操作具备原子性,读线程得到的数据一定是符合奇偶校验的

测试发现,在 x86 64 机器上, int64 的读写操作确实具备原子性

package main

import (
	"log"
	"math/rand"
	"sync"
)

func check(v int64) bool 
	var num int = 0
	for i := 0; i < 64; i++ 
		if v&0x01 != 0 
			num++
		
		v = v >> 1
	
	return num%2 == 0


func write(p *int64) 
	v := rand.Int63()
	if check(v) 
		v = v ^ 0x01
	
	*p = v

func main() 
	var wg sync.WaitGroup
	var val int64
	write(&val)

	for i := 0; i < 10; i++ 
		wg.Add(1)
		go func() 
			defer wg.Done()
			for i := 0; i < 10000000; i++ 
				write(&val)
			
		()
	

	go func() 
		for 
			v := val
			if check(v) 
				log.Fatalf("atomic test faile, val = %d", v)
			
		
	()

	wg.Wait()
	log.Printf("test finished")


以上是关于int64的读写操作是否具有原子性质的主要内容,如果未能解决你的问题,请参考以下文章

C++ 对 int 的读写是原子的吗?

我可以将 std::atomic<int64> 放在共享内存中并期望原子操作吗?

非原子的 64 位操作

原子操作--sync/atomic的用法

改进来自 InterlockedCompareExchange() 的原子读取

共享变量的并发读写