【问题标题】:Using atomic_fetch_add in C11 to do manual reference counting在 C11 中使用 atomic_fetch_add 做手动引用计数
【发布时间】:2013-09-19 17:20:04
【问题描述】:

我正在编写一个库,其中另一种语言的连接库只能理解 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 是什么意思,我应该使用什么来进行引用计数?有关系吗?

【问题讨论】:

    标签: c reference-counting c11


    【解决方案1】:

    我认为你的设计是正确的,除了 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应该是acquire操作,release应该是release操作,但是两者都使用full barrier也是可以的。

    【讨论】:

    • 结构体是按值传递的,引用计数是为了在数据类型是指向某个东西的指针时释放内存。通过使用指向计数器的指针,复制的是指向计数器的指针,而不是计数器本身。显然我需要初始化 refcount。我可以做一个指向value 的指针,但我试图避免指向指针并尽可能多地保留在堆栈上。
    • 我认为这种设计没有意义。
    • 我不知道为什么这个答案被接受了。考虑有一个 refcount 1 的实例,然后复制它并保留它,如果你使用 int 而不是 int*,那么原始实例仍然有 refcount 1,当你释放它时,它刚刚被释放,使得复制的实例持有一个释放的指针。
    猜你喜欢
    • 2015-12-21
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多