有没有办法设计这个“静态类”,以便它是线程安全的?

时间:2013-04-26 14:00:40

标签: c++ design-patterns c++11 thread-safety

我有一个所有方法都是静态的类,如下所示:

class A { 
public:
   static std::string getA() { GlobalData::alfa; }
   static std::string sum(int x, int y) { ... }

   static int convert() { ... }

};

我需要A可以是线程安全的。 Whitch是更好的设计吗?我需要在这样的非静态方法中转换所有方法吗?

class B { 
public:
   std::string getA() { g.alfa; }
   std::string sum(int x, int y) { ... }
   int convert() { ... }

private:
   GlobalData g;
};

考虑GlobalData是一个简单的POD:

struct GlobalData
{
   static std::string foo;
   static int bar;
   ...
}

2 个答案:

答案 0 :(得分:2)

您可以保留类A的原始布局,甚至将其更改为命名空间,但是如果它包含的数据必须将GlobalData结构定义为线程本地存储,则必须将其定义为具体到每个线程:

 struct GlobalData {
    static thread_local std::string alfa;
    // other members here
};

您可能需要调用一个函数来根据每个线程的需要初始化数据。

请注意,如果已定义所有成员static,您也可以将该结构转换为命名空间:

namespace GlobalData {
    thread_local std::string alfa;
    // etc.
}

namespace A {
   std::string getA() { return GlobalData::alfa; }
   std::string sum(int x, int y) { /* ... */ }

   int convert() { /* ... */ }
}

可以提高您的代码可读性。

同样的规则应适用于原始代码中必须成为特定于线程的任何全局范围的数据。

答案 1 :(得分:1)

更好的设计是没有A使用静态实现。这意味着您创建一个A实例并通过依赖注入在客户端代码中使用它。

然后,您可以使用标准同步原语实现对A数据的RW访问。

由于A具有静态且A不是注入依赖项,因此内部使用A的代码将在要在A的实现中添加的同步原语上进行同步。这引入了潜在的死锁,这些死锁在客户端代码中是完全不可见的,可能很难找到和诊断(取决于A客户端代码交互的复杂性)。