我在 C 库中有全局静态变量,它们在多线程运行中生成异常。我需要以某种方式使它们安全(即,每个线程应该与这些变量的不同实例相关)。有什么推荐的方法吗?
4 回答
第一个问题:
- 线程需要自己的变量副本吗?
- 还是他们需要协调对单个共享副本的访问?
如果您需要前者,其他答案已经对“线程本地存储”提出了建议。
如果您需要后者,那么您需要以某种方式确保这些变量上有适当的互斥锁(互斥锁的范围是您面临的问题之一),并且线程都使用互斥锁并释放互斥锁。这更棘手。您甚至可能需要提供控制对变量的访问的函数。
标准变量errno
可以是可修改的左值:
extern int *_errno_func(void);
#define errno (*(_errno_func)())
在线程应用程序(使用 -DREENTRANT 编译)中,会发生这种情况;在 MacOS X 上,这似乎是无论如何都会发生的事情(它们使用名称__error
而不是_errno_func
; 两者都在实现的命名空间中)。
您可能想要或最终不得不为您的变量做类似的事情。您说它们是静态的这一事实使情况有所改善。您只有一个文件要处理(除非您足够粗心,将指向这些变量的指针传回 - 或 on - )。
您需要的是TLS(Thread Local Storage),也称为线程特定数据或线程私有数据。这种机制可以保证每个线程访问自己单独的数据副本,而不用担心与其他线程同步访问。
使用 TLS 有两种方法:
隐式:使用关键字
Windows: __declspec(thread) int tls_var = 10;
带有 GCC 的 Linux: __thread int tls_var = 10
显式:使用特定的 TLS 相关 API
视窗:
- tlsAlloc():为tls数据分配内存
- tlsFree():释放tls数据的内存
- TlsSetValue():设置 tls 的值
- TlsGetValue():获取 tls 的值
有关详细信息,请参阅 MSDN。
带有 GCC 的 Linux:
- pthread_key_create() : 创建 tls 数据
- pthread_key_delete() : 破坏 tls 数据
- pthread_getspecific() : 获取 tls 的值
- pthread_setspecific (): 设置 tls 的值
大多数编译器都有一些指定线程本地存储的方法。假设它可用,这就是你想要的。