3

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

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

   static int convert() { ... }

};

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

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;
   ...
}
4

2 回答 2

2

您可以保留 class 的原始布局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() { /* ... */ }
}

这提高了您的代码可读性。

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

于 2013-04-26T14:29:31.287 回答
1

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

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

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

于 2013-04-26T14:09:43.487 回答