线程本地变量和非线程本地变量同名是否可行?

8

我有一个线程本地变量envptr,还有一个非线程本地变量也叫envptr。后一个变量仅在单个线程中使用,其运行代码不会看到线程本地变量声明。不同的线程使用线程本地变量,每个线程都不看到,也不需要看到非线程本地变量的声明。

这种情况是否可能并产生定义良好的行为?我在x86上使用linux 32位和64位。


有没有示例代码,说明一个 envptr 如何使用 __thread 进行修饰,而另一个则不是?我唯一能想象到的方式是在两个不同文件中使用非外部变量..如果是这样的话,那么它似乎可以在这种情况下简单地回答。 - user166390
1
@pst 是的,就是这样做的。它们在cpp文件中声明,并在头文件中提供了一个函数Env *getEnv();。每个.cpp文件都有不同的定义。使用TLS版本的线程运行在与使用非TLS变量的主线程加载到同一进程中的.so文件中的代码上(这是由REPL shell使用的LLVM JIT编译器)。 - Johannes Schaub - litb
我已投票关闭,因为我认为它有一个非常简单的解决方案:我将只是使用不同的名称来链接到DLL的.cpp文件以及链接到主可执行文件的.cpp文件。编辑:这将限制.so文件的适用性,所以我仍然希望尝试其他方法。 - Johannes Schaub - litb
3个回答

4

它们是相同的变量吗?换句话说,它们的链接是什么?

如果它是外部的,那就不是。如果它是内部的,那就没问题,除非两个定义都出现在同一个文件中

如果没有链接,那就没有问题。

除非我忽略了什么,thread_local对链接没有影响,因此通常的规则适用(在一个翻译单元中定义变量thread_local而在另一个翻译单元中未定义违反了一次定义规则)。

然而,我认为标准存在一个错误(§7.1.1/1)。标准规定:“如果在任何变量声明中出现thread_local,则在该实体的所有声明中都必须存在。”没有明确说明不需要诊断,或者违反此规则是未定义行为,因此编译器必须诊断错误。当然,如果你在命名空间作用域下定义:

thread_local int i;

在一个翻译单元中,以及:
int i;

如果在另一个地方出现错误,则编译器可能无法诊断错误(我相当确定委员会不想要求这样做)。我的猜测是意图是未定义的行为。


1
是的,变量是外部的,所以很遗憾我的想法行不通。那我会尝试其他方法。 - Johannes Schaub - litb

3

这样做应该可以正常工作并产生正确的行为,因为这两个变量是两个不同的变量。

我强烈建议不要这么做,因为这只会使软件难以维护。无论这种行为是否正确,代码的可读性似乎更重要 - 对于具有截然不同行为的两组数据使用相同的变量名称似乎存在问题。


@Yakk 作者使用“OK”(我加引号)来指代问题:“这种情况是否可能并产生定义行为?” - user166390
我同意“这是可能的并且会产生定义行为”。 :) 但我强烈建议避免将全局变量(和线程本地变量)命名为与局部变量相同--我建议选择一个命名方案。甚至只需按约定将其放入namespace thread_local或其他名称空间中。 - Yakk - Adam Nevraumont
@Yakk 啊,好的,我会给它取一个不同的名字!如果你把它作为答案发布,我会接受它! - Johannes Schaub - litb
1
它们是否是两个不同的变量取决于链接。如果链接是外部的,它们就是同一个变量。(我赞同@Yakk的建议将它们放在不同的命名空间中。虽然名称“thread_local”不能用作命名空间名称。) - James Kanze
@JamesKanze 哈哈,说的没错。 :) 那么,namespace virtual 这样的东西怎么样? - Yakk - Adam Nevraumont

3

根据您的描述,似乎它们是两个不同的变量(它们中的任何一个都从未遮盖另一个),在技术层面上这似乎是完全可以的。

尽管如此,我永远不会建议这样做,因为最有可能发生的事情是,在未来的维护中,某人会对其含义感到困惑,并且尝试理解代码会导致更多问题。


1
它们是否是两个不同的变量取决于名称的链接(这不受“thread_local”的影响)。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接