Thread safety of map container

Sep 13, 2010 at 8:18pm
I'm trying to use a map container to store a variety of variables that are shared between several threads. I've read that the map container is thread safe on reads, but not writes. However I remember seeing that a map may be thread safe on edits. For example, if I were to fill the map with entries for every variable in advance, would future reads and edits of those entries be thread safe (no removal or addition of elements, only edits)?
Sep 13, 2010 at 8:53pm
Not unless you protect the edits by using some kind of thread locking device such as a mutex or binary semaphore. Multiple, simultaneous reads are the only think that I can think of that are thread safe. You cannot have one thread modifying a value while another thread is attempting to read the value. It makes no difference that you are only trying to modify an existing value. You still cannot modify and read the same element from different threads simultaneously.
Sep 13, 2010 at 9:36pm
But reading one element while another thread edits a different element should be ok? I can use locks to protect individual elements from a simultaneous read and write, but I don't want to delay all the threads because of one write.
Sep 14, 2010 at 5:39pm
I don't see how you could accomplish that but good luck in finding a solution. Let us know if you figure something out. That is a perplexing problem. Personally I think that you are better off with a single synch object for that container. keep it simple and I doubt that you will notice any problems.
Sep 14, 2010 at 6:22pm
I think writes might be different than edits for a map because it's often stored in a data structure that automatically re-balances. Assuming you aren't writing new elements, you can create a map of multi-reader locks, such that

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object Read(Key key)
{
  RWLock * lock = _mapLocks[key];
  lock->read_lock();
  object obj = _mapObjects[key];
  lock->read_unlock();
  return obj;
}

void Write(Key key, object obj)
{
  RWLock * lock = _mapLocks[key];
  lock->write_lock();
  mapObjects[key] = obj;
  lock->write_unlock();
}


Though there is likely a more elegant solution - I do relatively little multi-threaded programming and so am a bit rusty :)

--Rollie
Sep 14, 2010 at 6:49pm
I had thought of that as well Rollie but what is the benefit? What you have done could be slower than simply using a single locking object because now there is an addtional lookup in addition to having to do the lock and unlock anyway. Either way every read and every write is going to lock a device. It is only a question of which one. The only way that can help is if there are thousands of reads and writes going on within a short time frame and if the OP is concerned about blocking and not about the general speed of the locking mechanism itself. Since a write operation might be fast anyway it might not be useful to implement that. It also matters how often a write occurs. If the write is infrequent I don't believe that solution will buy you a whole lot. It is worth discussing if the OP is willing to give us more details.
Last edited on Sep 14, 2010 at 6:55pm
Sep 16, 2010 at 2:47pm
I'm currently using something along the lines of Rollie's suggestion. For each element in the map of variables I have a corresponding mutex in a different map such that every read/write locks a single element. Since I am usually reading or writing just a few variables at a time I'm hoping this is faster than locking the whole map. But, since some of the threads could be setup to do all of their reads/writes at once and not too frequently, locking the entire map may turn out to be a better solution. For now the former solution is easier to work with though, because I can just overload the [] operator in my new thread-safe map class and treat it like a normal map.

As I continue to develop the project I may decide to test the performance of the two solutions. Alternatively, I might try splitting up the data under separate locks based on groups of variables typically accessed together once I have a better idea what those groups will be. In case you're curious this is part of a robotics application where there are sensors and outputs in continuous communication, controls being run with those sensors/outputs, and some communication with a user interface. The code is running on a small embedded system, so maintaining performance is somewhat of a concern.

Thanks for the suggestions so far.
Topic archived. No new replies allowed.