0

I have a std::map myMap and a std::atomic myLock.

The write is:

if(myLock == 0)
{
   myLock++;
   myMap.insert(key, value);
   myLock--;
}

If I do something like this without locking from another thread, is this considered undefined behavior? The key thing is, I do not mind if the results are not accurate (ie a value in the map updated after I iterated past it). I just don't want to crash.

MyConstIterator endIt = mMap.cend();
for(MyConstIterator it = myMap.cbegin(); it != endIt; ++it)
{ 
}

I'm trying to achieve lock less reads without a mutex, but I know std::map is not thread safe. Do I have to add to the atomic lock to avoid a crash?

user99999991
  • 1,351
  • 3
  • 19
  • 43
  • Why are you opposed to using a mutex? – mascoj Feb 20 '18 at 22:23
  • 1
    Your use of lock won't make your map thread safe. Think about it. Two threads can read myLock == 0 and head into your brace. You need a mutex. – Robinson Feb 20 '18 at 22:23
  • 2
    There is no lock at all in the provided code. It is undefined behavior from here to Kathmandu. – SergeyA Feb 20 '18 at 22:24
  • thanks, that's an answer. feel free so I can accept. – user99999991 Feb 20 '18 at 22:25
  • There are 2 moments to consider 1. `std::atomic` is not free and has it's price. 2. if you think that it is so easy to beat implementation that written by experts by writing this "spinlock", think again and test - you will be surprised. – Slava Feb 22 '18 at 04:19
  • Not the point of the question, but thank you. I already understand. And as specified, this is not a spin lock. – user99999991 Feb 22 '18 at 20:23

1 Answers1

5

Your use of lock won't make your map thread safe. Two threads can read myLock == 0 and head into your brace.

You need a mutex. This answer on locking may be useful.

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
Robinson
  • 9,666
  • 16
  • 71
  • 115
  • So what if I were to change it to ++myLock == 1 check instead? It's atomic, so the threads can't possibly see 1 at the same time. – user99999991 Feb 20 '18 at 22:33
  • @user99999991, Do you have a specific reason for trying to write your own lock? – merlin2011 Feb 20 '18 at 22:33
  • I do not want to wait on a mutex. If there is a lock, I just want to continue on. It's a very lightweight piece of code that doesn't have to ensure it's writing in lock step. Atomic seemed to be the best route. – user99999991 Feb 20 '18 at 22:36
  • 5
    Mutex has a [trylock](http://en.cppreference.com/w/cpp/thread/mutex/try_lock) function. There's also [Boost Lockfree](http://www.boost.org/doc/libs/1_55_0/doc/html/lockfree.html). – Robinson Feb 20 '18 at 22:38
  • I will take a look at it. But for curiosity sake, does ++m_Lock == 1 hold the thread safety? Because m_Lock is atomic, both threads should be safe when writing. When reading, I do not think it is safe unless I add a similar ++m_Lock == 1 check correct? I made a simple console app that continuously reads in 1 thread, and 3 other threads continuous writing. It appears to work, but I do not know if Im actually in undefined behavior. – user99999991 Feb 21 '18 at 06:12
  • 1
    There are things like instruction reordering to consider, though I'm not an expert on this (or anything), I do remember [reading about such things in Dr Dobbs](http://www.drdobbs.com/cpp/lock-free-code-a-false-sense-of-security/210600279) a while back when I was thinking a lock-free impl would be a good idea. – Robinson Feb 21 '18 at 10:27
  • @user99999991 `std::atomic` only makes operations on atomic itself thread safe and nothing else, `std::mutex` is different, so no your spin lock will not work properly and most probably would be less efficient than standard mutex. – Slava Feb 22 '18 at 04:16