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

时间:2022-10-22 10:38:39

I have a class with all methods static, like this:

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

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

   static int convert() { ... }

};

I need that A could be thread-safe. Whitch is the better design for do that? I need to convert all methods in a non-static method like this?

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

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

private:
   GlobalData g;
};

Consider that GlobalData is a simple POD like this:

考虑GlobalData是一个简单的POD,如下所示:

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

2 个解决方案

#1


2  

You can keep the original layout of class A, or even change it to a namespace instead, but you will have to define the GlobalData struct as thread local storage, if the data it contains must be specific to each thread:

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

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

You will probably need to call a function to initialize the data as needed for each thread.

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

Note that you could also turn that struct into a namespace if all the members have been defined static:

请注意,如果所有成员都已定义为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() { /* ... */ }
}

which improves your code readability.

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

The same rule should apply for any piece of data of global scope in your original code which must become thread specific.

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

#2


1  

A better design would be to not have A use a static implementation at all. This would mean you create an A instance and use it in client code through dependency injection.

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

Then, you can implement the RW access to A's data, using standard synchronization primitives.

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

Since your A has static state and A is not an injected dependency, the code using A internally would be synchronized on the synchronization primitives you want to add in A's implementation. This introduces potential deadlocks that are completely invisible from client code, that could be difficult to find and diagnose (depending on the complexity of the interactions of client code of A).

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

#1


2  

You can keep the original layout of class A, or even change it to a namespace instead, but you will have to define the GlobalData struct as thread local storage, if the data it contains must be specific to each thread:

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

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

You will probably need to call a function to initialize the data as needed for each thread.

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

Note that you could also turn that struct into a namespace if all the members have been defined static:

请注意,如果所有成员都已定义为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() { /* ... */ }
}

which improves your code readability.

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

The same rule should apply for any piece of data of global scope in your original code which must become thread specific.

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

#2


1  

A better design would be to not have A use a static implementation at all. This would mean you create an A instance and use it in client code through dependency injection.

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

Then, you can implement the RW access to A's data, using standard synchronization primitives.

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

Since your A has static state and A is not an injected dependency, the code using A internally would be synchronized on the synchronization primitives you want to add in A's implementation. This introduces potential deadlocks that are completely invisible from client code, that could be difficult to find and diagnose (depending on the complexity of the interactions of client code of A).

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