如何在线程安全的 C 库中有效地实现句柄

How to implement a handle efficiently in thread safe C-library

我有一个相当复杂的符​​合 C99 的共享库。它包含大量的全局变量和许多短函数,但只有少数是用户直接使用的。

我想将它重构为一个线程安全的库。为此,我会让用户将一个句柄传递给每个函数。该句柄将是一个指向包含以前全局变量的结构的指针。

在这种情况下性能很重要,我不想危及它。实现句柄需要注意什么?例如,典型的函数如下所示

void calculate(){
    for (int i=0; i<N; i++){   
        particle[i].x += G * particle[i].y;
        other_function_that_does_something_to_particle();
    }
}

天真地,我会添加这样的句柄

void calculate(struct Handle* h){
    for (int i=0; i<h->N; i++){   
        h->particle[i].x += h->G * h->particle[i].y;
        other_function_that_does_something_to_particle(h);
    }
}

这看起来效率很低。有没有更好的方法?

传递指针的成本通常是微不足道的。它对架构有更大的影响,其中参数通过堆栈传递,而当参数通过寄存器传递时稍微小一些。

使用const 指针(指向常量数据的指针)。当数据可以被其他线程修改时,使用 volatile 字段或指针说明符。并使用 restrict.

所有类型说明符都有一定的影响。例如,当处理没有 restrict 的多个引用时,编译器可能被迫重新读取值,即使它已经读取了它们。等等。

值得一读:https://en.wikipedia.org/wiki/Restrict

那不一定慢。在某些架构上,它甚至可以更快,因为它们无论如何都必须将全局变量的地址加载到寄存器中(例如 ARM)。只需检查您平台的 PCS 和 ABI 以确保如何最好地传递参数,以便您在寄存器中传递 handle/context 指针。

我会让 h 本身保持不变,但是:struct Handle * const h。这可以防止 h 被意外修改。

如果可以移动到 C11,请查看 _Thread_local 存储 class 说明符。这可能就是你想要的。但是,如果手动实施可能更有效,则取决于您的系统。