Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Map Concurrent Insertion and Reading by Two threads

There are two threads where one will insert into the map and the other will find from the map.

map<string,object>* mapA;

If thread A will insert the configuration object into the Map w.r.t the string key.

Where the thread B will try to find with the same string key. If not present it will try again until the string key is found by it.

Will it cause a crash or data corruption in the process , if thread A inserts at the same time when thread B is read the key ? Is there synchronization needed here?

While testing with a sample application i dint face any type of crash or corruption

like image 406
Sel_va Avatar asked Sep 28 '15 04:09

Sel_va


1 Answers

The container can be accessed without any locking mechanism, only if all the threads involved are reader threads.

The thread safety of stl containers has been discussed here:

Why does the C++ STL not provide a set of thread-safe containers?

Quoting the spec:

23.2.2 Container data races

"implementations are required to avoid data races when the contents of the contained object in different elements in the same container, excepting vector, are modified concurrently."

In short, in your case, since both insert and find are involved from different threads, locking is needed.

Use-case where locking is needed: If you have a datastructure on which insert and find are being performed intermittently/concurrently, then locking is needed .

Use-case where locking is not needed: If you have a datastructure that is populated at one shot and then subsequently, only finds are performed then locking is not needed.

Here is the source code:

STL map uses rb-tree internally.so, here is a look at rb-tree find method.

template <class _Key, class _Value, class _KeyOfValue, 
          class _Compare, class _Alloc>
typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator 
_Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::find(const _Key& __k)
{
  _Link_type __y = _M_header;      // Last node which is not less than __k. 
  _Link_type __x = _M_root();      // Current node. 

  while (__x != 0) 
    if (!_M_key_compare(_S_key(__x), __k))
      __y = __x, __x = _S_left(__x);
    else
      __x = _S_right(__x);

  iterator __j = iterator(__y);   
  return (__j == end() || _M_key_compare(__k, _S_key(__j._M_node))) ? 
     end() : __j;
}

As seen, there is no lock used and it makes sense since the overhead of lock is not really needed/desired for non-threaded applications.

like image 55
basav Avatar answered Sep 30 '22 02:09

basav