有没有办法设计这个"static class",使其是线程安全的?

Is there a way to design this "static class" so that it is thread-safe?

本文关键字:线程 安全 static 有没有 class      更新时间:2023-10-16

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

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

您可以保留类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() { /* ... */ }
}

这提高了代码的可读性。

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

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

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

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