gpt4 book ai didi

c - Linux下实现窗口函数InterlockedExchange

转载 作者:行者123 更新时间:2023-11-30 19:30:10 24 4
gpt4 key购买 nike

在此链接中achieve GCC cas function for version 4.1.2 and earlier我问一个问题,使用 compare_and_swap 函数来实现内置函数 __sync_fetch_and_add 这是我的最终代码,在 x86 和 x64 上运行良好(在 CentOS 5.0 上测试) 32 位 和 CentOS 7 64 位)。

<小时/>

这是我的代码:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

static unsigned long count = 0;

int sync_add_and_fetch(int* reg, int oldval, int incre)
{
register char result;
#ifdef __i386__
__asm__ volatile ("lock; cmpxchgl %3, %0; setz %1"
: "=m"(*reg), "=q" (result)
: "m" (*reg), "r" (oldval + incre), "a" (oldval)
: "memory");
return result;
#elif defined(__x86_64__)
__asm__ volatile ("lock; cmpxchgq %3, %0; setz %1"
: "=m"(*reg), "=q" (result)
: "m" (*reg), "r" (newval + incre), "a" (oldval)
: "memory");
return result;
#else
#error:architecture not supported and gcc too old
#endif

}


void *test_func(void *arg)
{
int i = 0;
int result = 0;
for(i = 0; i < 2000; ++i)
{
result = 0;
while(0 == result)
{
result = sync_add_and_fetch((int *)&count, count, 1);
}
}

return NULL;
}

int main(int argc, const char *argv[])
{
pthread_t id[10];
int i = 0;

for(i = 0; i < 10; ++i){
pthread_create(&id[i], NULL, test_func, NULL);
}

for(i = 0; i < 10; ++i){
pthread_join(id[i], NULL);
}
//10*2000=200000
printf("%u\n", count);

return 0;
}

现在我还有一个问题,如何在Linux中实现InterlockedExchange功能,InterlockedExchange就像上面的代码一样,有一个 __i386____x86_64__ 版本。只要使用上面参数类型不匹配的代码,也许汇编代码就会被重写。

最佳答案

交换很容易;您不必返回任何状态或任何内容。它xchg总是交换,因此您只需返回旧值和/或状态 like for cmpxchg .

static inline
int sync_xchg(int *p, int newval)
{
// xchg mem,reg has an implicit lock prefix
asm volatile("xchg %[newval], %[mem]"
: [mem] "+m" (*p), [newval] "+r" (newval) // read/write operands
:
: "memory" // compiler memory barrier, giving us seq-cst memory ordering
);
return newval;
}

使用 int32_t 可能会更好,但 int 在所有相关 ABI 中都是 32 位。此外,该汇编适用于任何大小的整数。 GCC 将选择 16 位、32 位或 64 位寄存器,这将意味着 xchg 的操作数大小。 (当没有寄存器操作数时,您只需要像 addl 这样的后缀,例如 lock; addl $1, (%0))

无论如何,我对此进行了测试,它可以正确编译 gcc4.1.2 on the Godbolt compiler explorer 。我无法访问 gcc4.1.1,但希望 "+m"[named] asm 内存操作数在该版本中不是新增内容。

+m 使编写防弹交换函数变得容易。例如没有 gcc 为同一变量选择两个不同的内存位置作为输入和输出的风险。

gcc4.1.2 的

gcc -O3 输出:

# 32-bit: -m32 -fomit-frame-pointer
sync_xchg(int*, int):
movl 4(%esp), %edx
movl 8(%esp), %eax
xchg %eax, (%edx)
ret # returns in EAX


# 64-bit: just -O3
sync_xchg(int*, int):
xchg %esi, (%rdi)
movl %esi, %eax
ret # returns in EAX

我还使用较新的 gcc 并单击 Godbolt 上的 11010 二进制按钮检查了该 asm 是否实际进行了汇编。有趣的事实:由于 GAS 接受 xchg mem,reg 或 xchg reg,mem,因此您可以使用 AT&T 或 Intel 语法 (-masm=intel) 编译此函数。不过,您的其他功能将无法使用。

关于c - Linux下实现窗口函数InterlockedExchange,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51617338/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com