5

我正在研究一个库的多线程实现。在这个库的一个模块中,有一些全局变量(在程序执行中经常使用)。为了使对这些变量的访问更加安全,我使用 Thread-local storage (TLS) 关键字声明了它们__declspec(thread)

这是对库外部函数的调用。此函数使用具有全局变量的模块:

for(i = 0; i<n_cores; i++)
    hth[i] = (HANDLE)_beginthread((void(*)(void*))MT_Interface_DimenMultiCells,0,(void*)&inputSet[i]);

通过这种方式,我猜库中使用的所有变量都将为每个线程复制。

当我在 x8 核处理器上运行程序时,完成操作所需的时间不会超过单进程实现所需时间的 1/3。

我知道不可能达到 1/8 的时间,但我认为至少 1/6 是可以达到的。

问题是:这些__declspec(thread)变量是造成如此糟糕表现的原因吗?

4

2 回答 2

6

如果您将它们声明为__declspec(thread)它们以前是全局的,那么您已经改变了程序的含义以及它的性能特征。

当变量是全局变量时,每个线程都引用一个副本。作为线程本地,每个单独的线程都有自己的变量,并且对该线程局部变量的更改仅在该线程中可见。

假设您真的想要线程本地,那么读取和写入线程本地变量确实比普通变量更昂贵。每当您面临需要很长时间才能执行的操作时,最好的解决方案就是完全停止执行。在这种情况下,有两种明显的方法可以做到这一点:

  1. 将变量作为参数传递,以便它驻留在堆栈中。访问堆栈变量很快。
  2. 如果你的函数经常读取和写入这个变量,那么在函数的开头复制它(到一个局部变量中),处理那个局部变量,然后在返回时,把它写回线程本地.

在这些选项中,通常首选前者。选项 2 有一个很大的缺点,即如果函数调用另一个使用此变量的函数,它就不能轻易应用。

选项 1 基本上相当于不使用全局变量(线程局部变量是全局的一种形式)。

当然,这一切都可能完全偏离标准,因为您对您的代码实际上在做什么几乎没有说什么。如果你想解决一个性能问题,你首先必须确定它在哪里,这意味着你需要测量。

于 2011-02-22T10:57:31.117 回答
5

答案是:您需要分析应用程序,并衡量花费最多时间的地方。如果它出现在经常引用 TLS 数据的函数中,那么“也许”可能就是答案。

即使在您自己编写的代码中,通常也很难找出性能不佳的原因:在两个简短段落中描述的程序中远程执行此操作更加困难。

配置文件,然后优化。

于 2011-02-22T10:23:57.110 回答