莱芜网站优化费用,跨境电商平台的特点,软文营销模板,网站访问量咋做如题#xff0c; x86_64处理器的指针赋值是原子操作吗#xff1f;说实话我很讨厌参与讨论那些似乎不确定东西#xff0c;倒不是说我对未知不敬畏#xff0c;而是参与讨论的人大多数都是似懂非懂#xff0c;对#xff0c;我说的不确定性指的是参与讨论的人的认知的不确定 x86_64处理器的指针赋值是原子操作吗说实话我很讨厌参与讨论那些似乎不确定东西倒不是说我对未知不敬畏而是参与讨论的人大多数都是似懂非懂对我说的不确定性指的是参与讨论的人的认知的不确定如果你自己都似懂非懂那么我说什么你都可以反驳我说些 “貌似可能并不绝对” 的词汇来让事情变得混乱。所以说我的意思是 以Intel的手册为准。 我觉得我应该收回上面的那句 “which is a pointer assignment operation, on the x86_64 platform which is an atomic operation.” 然后重新说出个所以然来。有了这段 权威描述 本文似乎该结束了。但是…show me the code 是个金句它鄙视的是 talk 因为 talk is cheap.那好吧按照这样看来上面那一段都是废话非常cheap那么下面就用代码说话吧。声明一下:以下无术语也不再引用任何cheap的东西。本文虽然以“指针赋值”为例但其实任何“intlonglong long”赋值均试用 。我在代码里强转来强转去的实际在暗示什么呢CPU和内存不了解什么是指针只有在执行的时候一个unsigned long才会 变成 指针。网络协议序列化时请 谨慎相信任何原子操作的承诺考虑一个指针p两个或者多个线程分别对它进行赋值long *p;// thread 1p a1;// thread 2p a2结果可以预期吗如果你笃信指针赋值是原子操作那么最终结果p不是a1便是a2这是确定的。然而Intel手册里说如果指针p跨越了cacheling的边界便不能保证赋值操作是原子的为了复现Intel的说法从而证明指针赋值并非原子的只需要给出一个反例即p既不是a1也不是a2。在编码之前我们先查一下自己实验的机器上的cacheline的大小rootzhaoya-VirtualBox:~/xdp/msvc# cat rootzhaoya-VirtualBox:~# cat /sys/devices/system/cpu/cpu1/cache/index0/coherency_line_size64OK64字节的cacheline我们下面就制造一个跨越64字节边界的指针直接看代码#include #include // 不让编译器自动扩充结构体对齐特征这个在网络协议以及序列号操作中很常见。#pragma pack(1)struct pack {// 60字节的paddingchar unsued[60];// cacheline仅剩下4字节仅够装指针p的4字节剩余4字节跨越到另一个cachelinelong *p;};#pragma pack()// 内存对齐粒度最小为1字节我设置64个元素的数组总有一个元素恰好是在64字节边界的struct pack pa[64];// 保存64字节边界的元素struct pack *used;long a 0x1122334455667788;long b 0x8877665544332211;void *write_value1(void *param){for (;;) {used-p (long *)a;// 不让编译器优化asm volatile( ::: memory);}return NULL;}void *write_value2(void *param){for (;;) {used-p (long *)b;asm volatile( ::: memory);}return NULL;}int main(int argc, char **argv){int i;long *p;pthread_t t1, t2;// for循环找到那个64字节边界的pack结构体元素for (i 0; i 64; i) {unsigned long addr;addr (unsigned long)pa[i];if (addr%64 0) {// 赋值给usedused (struct pack *)addr;break;}}pthread_create(t1, NULL, write_value1, NULL);pthread_create(t2, NULL, write_value2, NULL);while (1) {p used-p;// 我们看能不能找到既不是a又不是b的pif (p ! (long *)a p ! (long *)b) {printf(%lx\n, (unsigned long)p);}}return 0;}跑一下呗我的天这意味着什么这意味着不加锁的指针赋值极其危险什么难道编译器不帮忙编译器只能尽量帮忙哦对了还有Linux内核的伙伴系统slab系统都只是尽量帮忙其余的事只能看造化。谁也不能保证你不会写出上面类似pack的结构体因此结构体的字段布局非常重要。即便这样你也不能保证结构体对象恰好被载入你希望的位置只要超过一个cacheline大小的结构体内部字段的赋值就一定小心再小心加锁影响性能不加锁怕跨越边界说白了这就是个手艺活。如果你想快速复现指针跨越cacheline的赋值非原子性直接加个修饰即可// 你也可以直接用aligned来固化地址对齐特征然则不真实struct pack pa __attribute__ ((aligned(64)));...int main(......used pa;不多说了深入什么单条指令的原子执行LOCK引脚cache一致性原子操作粒度等等细节无益于解决实际问题至于其它体系结构摸都摸不到(我是说我自己)更显得纸上谈兵到此为止了。浙江温州皮鞋湿下雨进水不会胖dog250博客专家发布了1546 篇原创文章 · 获赞 4762 · 访问量 1057万他的留言板关注标签x86,long,64,赋值,字节,指针,pack来源 https://blog.csdn.net/dog250/article/details/103948307