我正在研究一个旧的遗留 ANSI C 系统,其中散布着很多全局变量。我是重构现有代码库的团队的一员,以使代码可重入和线程安全。我在这里找到了关于编写线程安全和可重入 ANSI C 代码的有用材料。
根据我(诚然不完美)的理解,我提出了一个关于如何进行的建议——但我已经提出了一些需要解决的问题,并决定最好来这里找出最好的方法在实际开始编码之前进行设计。
/******************************************************************/
/* */
/* CURRENT situaton: */
/* Global variables scattered accross a multitude of source files */
/* */
/******************************************************************/
static struct myStruct some_struct;
static long instance_counter;
static char[MAX_STR_LEN] instance_name;
static dbConnection * db_conn;
static SharedMemoryPtr * shrmem_ptr;
/*******************************************************************/
/* */
/* PROPOSED solution: */
/* Wrap all global variables into one thread local struct and */
/* provide getter/setter* funcs for the variables (of course, this */
/* means that I will have to modify existing code to use the */
/* context variable and the getter/setter methods instead of */
/* directly accessing the global variables) */
/* */
/*******************************************************************/
/* Thread local variables stored in ONE source file */
struct myStruct some_struct;
long instance_counter;
char[MAX_STR_LEN] instance_name;
dbConnection * db_conn;
SharedMemoryPtr * shrmem_ptr;
/* Thread local variable that provides getter/setter funcs to 'globals' */
typedef struct _ctx
{
/* Getter functions */
variable1_type (getter_func1*)(void);
variable2_type (getter_func2*)(void);
/* Setter functions */
void (setter_func1*)(variable1_type v1);
void (setter_func2*)(variable2_type v2);
} Context;
我有三个主要问题:
我采取的方法是好的(即最好的还是更好的方法之一)?如果没有,是否有更好的推荐(即“最佳实践”)方式来做我想做的事情?
如果在一个线程中更改了线程局部变量,该更改是否会反映在其他线程中?如果答案是否定的(我怀疑是这样),那么这意味着两个线程可以使用不同的变量值运行。在我能想到的几乎所有应用程序中,这是不可接受的——那么现有的多线程应用程序如何避免这种情况呢?我的基本理解告诉我,在写入之前必须获取锁,并且当有任何线程读取时,写入线程必须阻塞。如果不是这种情况,那么我将不胜感激澄清正确的事件顺序。我也很欣赏一些伪代码,这些伪代码将展示如何使用我的示例数据结构来实现这个读/写操作。
出于显而易见的原因,我在上下文结构中编写的 getter 函数伪代码理想情况下应该返回指针(以避免在每次检索时复制潜在的巨大数据结构)。但是,根据我之前在问题中提到的 IBM 页面(提供的链接):
可重入函数不会在连续调用中保存静态数据,也不会返回指向静态数据的指针。所有数据都由函数的调用者提供。
所以(据我了解),getter 函数不能返回指向静态数据的指针(除非我弄错了)。有人可以澄清一下。此外,如果我不应该从 gettter 函数返回指针,有什么方法/技术可以用来防止/避免返回数据的副本(正如我所说,一些结构非常庞大/沉重)。
[[在旁边]]
我正在 Ubuntu 12.04 LTS 上开发,所以我对 POSIX 兼容的解决方案很感兴趣。