【问题标题】:Do we need to have static lock for static member variable of the class in c++我们是否需要对c ++中类的静态成员变量进行静态锁定
【发布时间】:2025-12-24 14:50:05
【问题描述】:

我有一个静态地图作为我班级的成员变量。 当我们必须访问这个地图时,我们需要有静态锁吗?

【问题讨论】:

  • 我认为一个简短的示例将有助于回答您的问题...
  • 这里需要更多上下文。
  • 欢迎来到 Stack Overflow,您可能需要查看 how to ask 部分以改进问题的措辞。
  • 你的问题中没有提到多线程,所以你不需要锁:)

标签: c++ locking


【解决方案1】:

如果您的 std::map 实例被声明为静态类,那么您的锁也需要为静态类。

当锁是非静态成员但映射是时,考虑使用映射处理单独对象的两个线程。

  • 对象 1 锁定本地锁并开始操作共享映射。
  • 对象 2 锁定其本地锁(请记住,它是一个单独的锁)并开始操作共享映射。
  • 繁荣/崩溃/燃烧

如果锁是class static,那么两个对象会共享锁,上面的场景也可以正常工作,一次只能有一个线程加锁。

当然还有其他方法可以在不使用static 的情况下共享锁,但这似乎不是您要问的。

【讨论】:

  • 但是你那个 OP 是怎么使用本地锁的?
  • @user1764961 他问他是否需要在映射静态时使锁成为静态,这使我相信他是在询问当映射成员是静态时锁成员是否需要是静态的。静态映射是共享的,非静态锁是对象本地的,组合不是很幸运。如果我读错了,我很乐意删除答案。
  • 不,不要删除它,即使你错了,因为它有用。
  • 你是完全正确的,如果你提到类静态(而不是函数静态或翻译单元静态又名内部链接。
  • @ArneMertz 是的,静态类...抱歉语言不精确。
【解决方案2】:

每个对象都需要一个mutex,它必须以同步方式使用。如 Joachim Isaksson 在他的回答中给出的示例所示,为一个对象设置多个互斥体将导致竞争条件。

static变量有不同的方式:

  1. 类静态(这可能是你的意思):

    class X {
      static map<A,B> mMap;
    };
    

    您在系统范围内只有一个对象。在这种情况下,映射的互斥锁也应该是类静态的,并且每当以需要同步的方式使用映射时都应该锁定。请记住,类静态成员的初始化不是线程安全的。

  2. 函数局部静态:

     class X {
       void foo() {
         static map<A,B> theMap{ /* ... */ };
       }
     };
    

    无论foo 本身是否是静态类,您在系统范围内都有一个对象。该对象的初始化保证是线程安全的。您还需要一个系统范围内的互斥锁。该互斥锁应该是foo 内的静态或类静态或全局。在后两种情况下,必须在每次调用foo 之前将其锁定。这是 Meyers 单例的经典用例:

     class X {
       static mutex mapMutex;
    
       static map<A,B>& getMap() {
         static map<A,B> theMap{ /* ... */ };
         return theMap;
       }
    
       void useMap() {
         lock myLock(mutex);
         getMap()[a] = b;
       }
     };
    
  3. 翻译单元静态(“全局静态”)

     static map<A,B> gMap;
    
     class X { /* ... */ };
    

    您在每个具有此类声明的翻译单元中都有一个对象,即如果它在 .cpp 中,您将获得一个对象。如果它在标题内,您会为每个包含该标题的翻译单元获得一个对象。该对象的互斥锁也应该是静态翻译单元,因为您需要与对象一样多的互斥锁。但是,我不建议在多线程环境中使用这种静态变量。

【讨论】:

    【解决方案3】:

    首先,您应该考虑在static 上阅读smth(也许可以试试this)。那是因为static 的含义取决于上下文。

    但这可能是一个复杂的问题,我相信你有这样的事情:

    class A {
        private:
            static std::map....
    
        public:
            void doSomethingWithMap() {
                //lock mutex
    
                //some action with map
    
                //unlock mutex
            }
    }
    

    如果是这种情况,那么您可能希望您的互斥锁成为此类的成员。这就是重点——这取决于您需要的范围。如果你需要在这个类的所有对象上全局锁定 - 你应该考虑使用静态类成员,如果你想对每个对象都有锁定 - 你应该只使用一个类成员。

    【讨论】:

    • 锁定每个对象不会有帮助,请参阅 Joachim 的示例。
    • 是的,我有类似的代码,但那个锁是一个成员变量,所以我必须使它成为静态成员变量来锁定静态 std::map?
    • @Arne Mertz 不会帮助什么?这取决于您需要解决的问题。每个对象都可以锁定 - 只需将互斥锁作为类成员(我在这个答案中写过)。
    • @user1393608 如果您需要 per_object 锁定 - 您不需要静态。如果你需要全局类锁——你需要一个。这是一个简短的版本:)
    • 谢谢,@user1393608 我会在我的成员变量 lock 之前添加静态
    【解决方案4】:

    不,通常你不需要静态锁。

    【讨论】:

    • 呃...如果他问我认为他是什么(他需要澄清),那么他绝对需要锁与地图相同的(静态)存储类。跨度>
    • 呃,这就是我说“一般”的原因。我们不知道他到底写了什么。
    • 是的,为什么会这样,“需要锁与地图相同的(静态)存储类”。
    • 我不会删除这个答案,因为它是正确的。随意投反对票。
    • 每个对象都需要一个锁,它应该被同步使用并且不是线程安全的。因此,如果只有 一个 对象要同步,那么您只需要 一个 锁,无论是全局的还是类静态的或函数静态的,都没有关系。