C语言 如何实现TAS(“测试和设置”)?

xriantvc  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(116)

有谁知道TAS的使用方法吗?
这段代码以后应该能够保护代码在获取和释放之间免受基于多线程的状态丢失。

typedef volatile long lock_t;

void acquire(lock_t* lock){
    while(TAS(lock))
        ;
}

void release(lock_t* lock){
    *lock = 0;
}

lock_t REQ_lock = 0;

int main(){
    acquire(&REQ_lock);
    //not Atomar Code
    release(&REQ_lock);
}
ctehm74n

ctehm74n1#

C11标准将原子类型引入语言。
其中之一是atomic_flag类型,它有一个相关的功能atomic_flag_test_and_set在这里,它是从标准:
C11工作草案部分7.17.8.1:

概要

#include <stdatomic.h>
_Bool atomic_flag_test_and_set(
    volatile atomic_flag *object);
_Bool atomic_flag_test_and_set_explicit(
    volatile atomic_flag *object,memory_order order);

说明

原子地将对象指向的值设置为true。根据订单的价值,内存受到影响。这些操作是原子读-修改-写操作

返回

从原子上讲,对象的值紧接在效果之前。
与之沿着的是它的姊妹操作atomic_flag_clear
7.17.8.2部分:

概要

#include <stdatomic.h>
void atomic_flag_clear(volatile atomic_flag *object);
void atomic_flag_clear_explicit(
    volatile atomic_flag *object, memory_order order);

说明

order参数不能是memory_order_acquire或memory_order_acq_rel。原子地将对象指向的值设置为false。根据订单的价值,内存受到影响。

返回

atomic_flag_clear函数不返回值

oxiaedzo

oxiaedzo2#

实现必须是特定于平台的,我不建议使用程序集,因为它的代码可移植性很差。最好使用目标操作系统自带的ready-to-go功能。下面是一个简单的Windows解决方案:

#include <winnt.h>

void acquire(LONG* lock, DWORD bit)
{
    LONG nMask = 1 << bit;
    while (_interlockedbittestandset(lock, bit))
    {
        while (*lock & nMask); // Inner read-only spin
    }
}

void release(LONG* lock, DWORD bit)
{
     _interlockedbittestandreset(*lock, bit);
}

bool try_enter(LONG* lock, DWORD bit)
{
     return !_interlockedbittestandset(*lock, bit);
}

// Usage #1
volatile LONG lockVar = 0;
acquire(&lockVar, 0);
// ... critical code ...
release(&lockVar, 0);

// Usage #2
if (try_enter(&lockVar, 0))
{
     // ... critical code ...
     release(&lockVar, 0);
}

您可以为不同的共享对象使用不同的位(0..31)。该函数保证一个原子操作,read here

6ioyuze2

6ioyuze23#

C语言的优点之一就是让你尽可能接近机器语言的边界,但不会更远。这是更远。
你可以寻求原子支持,这在一些C扩充标准中提供,但这是一个问题。
在汇编中编写TAS。限制用于TAS的变量的可见性,以进行遏制。对于任何给定的体系结构,它应该不超过少数几行组装。你的程序将包含它的依赖性,而缺乏包容性是过去十年C增强的关键缺陷之一。

相关问题