使用线程局部存储将具有全局变量的单线程遗留代码转换为多线程代码

时间:2010-09-13 14:49:13

标签: c++ multithreading thread-local-storage

我有一个遗留C / C ++代码的代码库,它包含许多访问全局静态变量的函数,因此不是线程安全的。我正在寻找有关如何转换此代码以使其线程安全的建议。在我看来,实现它的一种方法是将静态变量转换为线程局部变量,或者将它们存储在线程局部存储中。这样做的好处是我不必重写大量使用函数传递额外上下文的代码,只需要线程不安全的函数本身。但在研究这个问题时,我没有找到很多关于这是好还是坏的建议。我所关注的一些具体问题是

  • 访问基于TLS的数据会明显变慢吗?
  • am我只是继续陷入使用全局变量的陷阱,因为“全局变量是坏的”,还是TLS抵消了全局变量是坏的论点?

任何其他想法也会受到赞赏。

6 个答案:

答案 0 :(得分:2)

首先,最好确定以可变方式访问哪些全局变量,哪些不是。可能有几种情况下变量实际上没有被设置修改,只是这些变量的初始化现在会给非确定性程序带来问题。那些变量,其中初始化顺序很重要,我将它们放在它们自己的类中,它可以传播到需要它们的每个单独的线程。

在那之后,我确信你的问题只能让自己复杂化。我一直在你身边和我的同情心。

答案 1 :(得分:1)

使用TLS的问题是你强制线程亲和力到你的客户端,他们必须知道这一点并编写他们的代码来相应地处理它。因此,如果他们有一个完成繁重工作的工作线程,那么他们将不得不将对您的库的所有调用封送到该工作线程上,即使对于简单的getter和setter也是如此。或者,如果某个其他组件在线程池线程(例如)上调用它们的组件,那么它们必须将该调用封送到其工作线程上。这不是世界上最糟糕的事情,但它可能非常不方便。我绝对更喜欢句柄/上下文模式(我维护一个使用TLS的库,有时候处理线程亲和性是一件苦差事。)

答案 2 :(得分:0)

嗯,从那里开始很容易。你可以只为线程本地进行条件编译。一些编译器,例如Visual Studio有自己的thread_local存储,您可以直接进入。

答案 3 :(得分:0)

就正确性而言,我认为没有理由认为这不起作用,只要线程没有其他可能导致冲突的含义。你需要确保你抓住所有全局变量并转换它们。

确定它是否明显变慢的最佳方法是分析代码的转换部分并查看。

话虽如此,我不知道这是最好的解决方案。全局变量就是这样,无论它们被称为什么,它们都会跟踪程序状态并调试整个噩梦。我会认真地建议长时间查看代码并一次重构一段不依赖于全局变量的线程安全代码。你将有一个更容易的调试时间,未来的维护者(或你自己)将在几年后感谢你。

答案 4 :(得分:0)

如果不了解您计划转换的每个变量的语义,只需将全局转换为TLS的自动化很可能是一个巨大的非生产性时间轴。其中一些可能需要保持全局并以线程安全的方式处理 - 其他可能非常安全地用作TLS。还有更多可能是线程安全的TLS,但是当您增加线程数时(例如,先前单客户机单线程套接字服务器中每个客户端/线程一个套接字),会导致糟糕的不可扩展设计。

你的平台/编译器选择什么btw?

答案 5 :(得分:0)

不是将所有变量存储在线程本地存储中,我认为最好将它们放入类中;如果原始代码主要是C,则可以将C代码包装在一个类中,然后可以将“全局”变量作为字段。在不同线程中运行的类的不同实例自然会看到这些变量的不同版本。