我有一个相当复杂的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);
}
}
看起来效率很低。还有更好的方法吗?
答案 0 :(得分:3)
传递指针的成本通常很低。它对体系结构有更大的影响,其中参数通过堆栈,而当参数通过寄存器时,参数更小。
使用const
指针(指向const数据的指针)。当数据可以被其他线程修改时,使用volatile
字段或指针说明符。并使用restrict
。
所有类型说明符都有一定的影响。例如,在没有restrict
的情况下处理多个引用时,即使已经读取了值,编译器也可能被迫重新读取值。等等。
答案 1 :(得分:2)
这不一定慢。在某些体系结构上,它甚至可以更快,因为它们必须将全局变量的地址加载到寄存器中(例如ARM)。只需检查您的平台的PCS和ABI,以确保如何最好地传递参数,以便在寄存器中传递句柄/上下文指针。
我会让h
本身保持不变,但是:struct Handle * const h
。这样可以防止h
被意外修改。
如果您可以转到C11,请查看_Thread_local存储类说明符。这可能就是你想要的。但是,如果手动实现可能更有效,则取决于您的系统。