0

I have a static map as a member variable of my class. Do we need to have static lock when we have to access this map?

user1393608
  • 1,299
  • 3
  • 16
  • 29

4 Answers4

8

If your std::map instance is declared class static, then your lock needs to be class static too.

Consider two threads working against separate objects using the map when the lock is a non static member but the map is.

  • Object 1 locks the local lock and starts manipulating the shared map.
  • Object 2 locks its local lock (it's a separate lock, remember) and starts manipulating the shared map.
  • Boom/crash/burn

If the lock is class static, the two objects will share the lock, and the above scenario will work well, only one thread can lock at a time.

There are of course other ways to share a lock without using static, but that does not seem to be what you're asking.

Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294
  • But how do you that OP is using local locks? – user1764961 Jun 28 '13 at 06:08
  • @user1764961 He asks if he needs to make the locks static when the map is static, which leads me to believe that he is asking whether the lock member needs to be static when the map member is static. A static map is shared, a non static lock is local to the object, the combination not being very lucky. If I'm reading it wrong, I'll be happy to delete the answer. – Joachim Isaksson Jun 28 '13 at 06:11
  • No, don't delete it, even if you are wrong, because it is useful. – user1764961 Jun 28 '13 at 06:13
  • You are perfectly right, if you refer to class-static (as opposed to function-static or translation-unit-static aka internal linkage. – Arne Mertz Jun 28 '13 at 06:21
  • @ArneMertz Yes, class static... sorry for the imprecise language. – Joachim Isaksson Jun 28 '13 at 06:22
0

You need exactly one mutex per object that has to be used in a synchronized way. Having multiple mutexes for one object will lead to race conditions as shown by the example Joachim Isaksson has given in his answer.

There are different ways of static variables:

  1. class static (wich is probably what you mean):

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

    You have exactly one object system-wide. In this case, the mutex for the map should be class static as well and should be locked whenever the map is used in a way that needs to be synchronized. Keep in mind, that initialization of class static members is not threadsafe.

  2. function local static:

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

    You have one object system-wide, regardless of wether foo itself is class static or not. Initialization of that object is guaranteed to be threadsafe. You need exactly one mutex system-wide as well. That mutex should be either static inside foo or class static or global. In the latter two cases, it must be locked before every call of foo. That is the classic usecase of the Meyers singleton:

     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. translation unit static ("global static")

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

    You have one object inside every translation unit that has such a declaration, i.e. if it is inside a .cpp, you get one object. If it is inside a header, you get one object for every translation unit that includes that header. The mutex for that object should be translation unit static as well, as you need as many mutexes as there are objects. However, I would not recommend using that kind of static variables in a multithreaded environment.

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
-1

First of all you should consider reading smth on static (Try this, maybe). That's because meaning of static depends on context.

But that's probably a complication, I believe you have something like this:

class A {
    private:
        static std::map....

    public:
        void doSomethingWithMap() {
            //lock mutex

            //some action with map

            //unlock mutex
        }
}

If that's the case, then you might want to have your mutex as a member of this class. That's the point - it depends on the scope you need. If you need to lock globally across all the objects of this class - you should consider using static class member, if you want to have lock per object - you should settle with just a class member.

Community
  • 1
  • 1
Wintermute
  • 1,501
  • 17
  • 22
  • locking per object won't help, see Joachim's example. – Arne Mertz Jun 28 '13 at 06:19
  • yes I have similar code but that lock is a member variable, so I have to make it static member variable to lock static std::map? – user1393608 Jun 28 '13 at 06:23
  • @Arne Mertz won't help what? It depends on the problem you need to solve. It's possible to have lock per object - just have mutex as class member (which I wrote in this answer). – Wintermute Jun 28 '13 at 06:32
  • @user1393608 if you need _per_object_ lock - you don't need static. If you need global class lock - you need one. That's a short version :) – Wintermute Jun 28 '13 at 06:33
  • Thanks, @user1393608 I will add static before my member variable lock – user1393608 Jun 28 '13 at 06:50
-2

No, generally you don't need a static lock.

user1764961
  • 673
  • 7
  • 21
  • Er... if he is asking what I think he is (he needs to clarify), then he most definitely needs the lock to be the same (static) storage class as the map. – Joachim Isaksson Jun 28 '13 at 05:43
  • Eh, that's why I said "generally". We don't know what exactly he wrote. – user1764961 Jun 28 '13 at 05:44
  • yes why is it so, "needs the lock to be the same (static) storage class as the map". – user1393608 Jun 28 '13 at 05:47
  • I will not delete this answer, because it is correct. Feel free to downvote as much as you like. – user1764961 Jun 28 '13 at 06:16
  • You need one lock per object that should be used synchronized and that is not threadsafe. So if there is only *one* object to synchronize, you need only *one* lock, be it global or class-static or function-static, does not matter. – Arne Mertz Jun 28 '13 at 06:18
  • Based on how the OP phrased the question, yes, it does matter. You can have global variable which is not explicitly declared as static and it will work. I bet the OP is not aware of that. – user1764961 Jun 28 '13 at 06:21