如何实现便携式指针比较和交换?

How can I implement a portable pointer compare and swap?

我在 a Whosebug answer 中找到 compareAndSwap 的代码:

boolean CompareAndSwapPointer(volatile * void * ptr,
                              void * new_value,
                              void * old_value) {
#if defined(_MSC_VER)
   if (InterlockedCompareExchange(ptr, new_value, old_value) == old_value) return false;
   else return true;
#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
   return __sync_bool_compare_and_swap(ptr, old_value, new_value);
#else
#  error No implementation
#endif
}

这是获得可移植快速代码的最合适方法吗(汇编内联除外)。

此外,一个问题是那些特定的 builtin 方法从一个编译器到另一个编译器具有不同的参数和 return 值,这可能需要一些额外的更改,例如此中的 if then else例子。

另一个问题是这些 builtin 方法在机器代码级别的行为,它们的行为是否完全相同? (例如使用相同的汇编指令)

注意: 另一个问题是,如果有许多受支持的平台,而不仅仅是本示例中的(WindowsLinux)。代码可能会变得非常大。

我会使用 硬件抽象层 ,(HAL),它允许通用代码通用 - 并且可以包含任何可移植源并为每个平台构建。

在我看来,这允许更好的结构化和更具可读性的来源。

为了让您更好地理解这个过程,我建议 Google 查找示例和解释。

希望这个简短的回答对您有所帮助。

[编辑] 我将尝试为 Bionix 做一个简单的例子,展示如何实现 HAL 系统...

  • A 先生希望在 'Tianhe-2' 和 'Amiga 500' 上申请 运行。他有交叉编译器等,并将在他的 PC 上构建这两个二进制文件。他想读取按键并打印到屏幕上。

mrAMainApplication.c 包含以下...

#include "hal.h"

// This gets called every time around the main loop ...
void mainProcessLoop( void )
{
   unsigned char key = 0;

   // scan key ...
   key = hal_ReadKey();

   if ( key != 0 )
   {
       hal_PrintChar( key );
   }
}

然后他创建了一个头文件(记住 - 这是一个例子,不是工作代码!)... 他创造了 hal.h ...

#ifndef _HAL_H_
#define _HAL_H_

unsigned char hal_ReadKey( void );
unsigned char hal_PrintChar( unsigned char pKey );

#endif // _HAL_H_

现在 A 先生需要两个单独的源文件,一个用于他的 'Tianhe-2' 系统,另一个用于他的 Amiga 500...

hal_A500.c

void hal_ReadKey( void )
{
    // Amiga related code for reading KEYBOARD
}

void hal_PrintChar( unsigned char pKey )
{
    // Amiga related code for printing to a shell...
}

hal_Tianhe2_VERYFAST.c

void hal_ReadKey( void )
{
    // Tianhe-2 related code for reading KEYBOARD
}

void hal_PrintChar( unsigned char pKey )
{
    // Tianhe-2 related code for printing to a shell...
}

A 先生然后 - 在为 Amiga 构建时 - 构建 mrAmainApplication.c 和 hal_A500.c 在建造天河二号时 - 他使用 hal_Tianhe2_VERYFAST.c 而不是 hal_A500.c

是的 - 我写这个例子有点幽默,这不是任何人的耳标,只是我觉得它使这个例子更有趣,希望有助于理解。

尼尔

看看 ConcurrencyKit,您可能可以使用更高级别的原语,这可能是大多数时候人们真正想要的。与有点 OS 具体的 HAL 相比,我相信 CK 适用于 Windows 和许多非 gcc 编译器。

但是,如果您只是对如何在各种 C 编译器上可移植地实现 "compare-and-swap" 或原子操作感兴趣,请查看该代码的工作原理。这都是开源的。

我怀疑细节可能会变得混乱,并且通常不会在这里为一般性 public 进行简单或有趣的阐述。

在现代 C 中,从 C11 开始,使用 _Atomic 作为类型限定,使用 atomic_compare_exchange_weak 作为函数。

较新版本的 gcc 和 clang 与 C11 兼容,并以可移植的方式实现这些操作。