2017-07-25 80 views
0

我有一些C代码充满了全局变量,我需要将其与我的项目链接在一起。这个外部项目是一个频繁更新的实时项目,因此重写代码以实现更好的多实例性并不是一个简单的选择。举一个具体的例子,假设我们有库代码(忽略unsafeness!):Linux上具有单独数据段的库的多个实例

// foo.c 
static char s_memory[256]; 
static int s_length; 

void foo_init(char **mem) 
{ 
    *mem = s_memory; 
} 

void foo_calc(char *mem) 
{ 
    s_length = strlen(mem); 
} 

int foo_result() 
{ 
    return s_length; 
} 

这是用来如下:

// test_foo.c 
char *data; 
foo_init(&data); 
strcpy(data, "Hello, world!"); 
foo_calc(data); 
printf("%s is %d characters long!\n", data, foo_result()); 

也能正常工作的单线程实例,但我们的团队希望在多线程环境下,显然这是可怕的错误运行此:

char *data1; 
char *data2; 
foo_init(&data1); 
foo_init(&data2); 
strcpy(data1, "Hello, world!"); 
strcpy(data2, "Goodbye cruel world!"); 
foo_calc(data1); 
foo_calc(data2); 
printf("%s and %s are %d and %d characters long!\n", 
     data1, data2, foo_result(), foo_result()); 

我希望我们可以做什么会是这样:

char *data1; 
char *data2; 
FOO_HANDLE inst1 = new_instance("foo.so"); 
FOO_HANDLE inst2 = new_instance("foo.so"); 
inst1.foo_init(&data1); 
inst2.foo_init(&data2); 
strcpy(data1, "Hello, world!"); 
strcpy(data2, "Goodbye cruel world!"); 
inst1.foo_calc(data1); 
inst2.foo_calc(data2); 
printf("%s and %s are %d and %d characters long!\n", 
     data1, data2, inst1.foo_result(), inst2.foo_result()); 

怎么能这样做呢?

+6

重写代码以正确完成工作。 –

+0

@JonathanLeffler我的确尝试过,但有5,6层的全局变量,混合模块静态变量,指向其他文件的全局变量,以及混搭的内存,以及指针复制的长链,解决生命周期很痛苦,当然另一个团队正在更新代码,因此合并他们的更改变成了PITA。理想情况下,其他团队应该重构他们的东西,当然,但... –

+1

有时软件可能非常僵硬。但是,我认为没有一种理想的方式来实现你想要实现的目标。如果你显示的代码代表你想要的代码,线程本地存储不会起作用。你必须编写使用'new_instance'来分配结构的代码(参数不相关) - 可能是一个指针,所以你可以编写'inst1-> foo_init(&data1)'等等。 d必须释放与句柄相关的数据,以避免内存泄漏。这是一条滑路。任何使用旧界面的东西都不能多线程使用。 –

回答

0

最简单的解决方法是将_Thread_local(或__thread)放在每个全局中,并从它自己的线程访问每个实例。

可能会发生的另一种黑客行为是在每次需要新实例时创建.so文件的新副本,以及dlopen。或者,你可以编写你自己的ELF加载器,允许同一个库的多个实例(并不像听起来那么难)。

所有这些都是不好的黑客,但你真的应该只是修复代码以删除所有全局变量。

+1

我不认为因为调用环境并不能保证每个'foo'客户端都有它自己的线程,或者每个对'foo'客户端的调用都在同一个线程上,TLS就可以工作。 –

+0

@ KenY-N:确实,这是一个问题。你可以通过包装所有的公共接口来获得一个上下文参数来解决这个问题,上下文只是运行函数的线程,而一个command + mutex + condvar结构可以与线程通信,但是这样做很重要作为糟糕的API的解决方案而言真的很沉重。 –

相关问题