在C11中使用atomic_fetch_add进行手动引用计数

时间:2013-09-19 17:20:05

标签: c reference-counting c11

我正在编写一个库,其中另一种语言的连接库只能理解C.我需要与std::shared_ptr类似的东西,其中所有权是共享的。在我的情况下,手动引用计数就可以了。

C11 supports atomic operations。我一直试图找到一个如何正确执行此操作的示例,但我能够找到的每个示例都与C ++ 11有关,后者有运算符重载。

基本上我要做的就是这样:

typedef struct {
    union {
        int integer;
        // ...
        char* cstring;
        void* ptr;
    };
    enum {
        Undefined,
        Integer,
        String,
        // ...
    } type;
    int* refcount;
} value;

void value_retain(value v) {
    ++(*v.refcount);
}

void value_release(value v) {
    if(--(*v.refcount) == 0) {
        // free memory, depending on type...
    }
}

我假设我需要将int*更改为atomic_int*。函数atomic_fetch_sub表示它返回“之前保存的值是obj指向的原子对象”。这让我相信我的功能看起来像这样:

void value_retain(value v) {
    atomic_fetch_add(v.refcount, 1);
}

void value_release(value v) {
    if(atomic_fetch_sub(v.refcount, 1) == 1) {
        // free memory, depending on type...
    }
}

这是否正确?我担心的是atomic_fetch_sub会返回 的值,而不是 的值。

memory_order的含义是什么,我应该用什么来引用计数?这有关系吗?

1 个答案:

答案 0 :(得分:4)

我认为你的设计是正确的,除了int* refcount;的类型和指针的错误使用。现在你没有任何东西可以指向它,所以你将通过将(不确定的)指针值传递给原子操作来调用未定义的行为。我不明白你为什么要使用指针。类型应为:

int refcount;

,代码应为:

void value_retain(value v) {
    atomic_fetch_add(&v.refcount, 1);
}

void value_release(value v) {
    if(atomic_fetch_sub(&v.refcount, 1) == 1) {
        // free memory, depending on type...
    }
}

至于order / barrier语义,retain应该是一个获取操作,release应该是一个release操作,但是对两者都使用完全障碍也是可以的。