Thread synchronisation for C++ map Thread synchronisation for C++ map multithreading multithreading

Thread synchronisation for C++ map


I understand that reading using the [] operator, or even modifying the elements with it is thread safe, but the rest of the operations are not.

Do I understand this correctly?

Well, what you've said isn't quite true. Concurrent readers can use [] to access existing elements, or use other const functions (like find, size()...) safely if there's no simultaneous non-const operations like erase or insert mutating the map<>. Concurrent threads can modify different elements, but if one thread modifies an element you must have some synchronisation before another thread attempts to access or further modify that specific element.

When a thread wants to "write" to the map, it should set a lock so no thread starts any "read" or "write" operation, and then it should wait until all "read" operations have completed, at which point it would perform the operation and release the locks. - After the locks have been released, all threads should be able to read freely.

That's not quite the way it works... for writers to be able to 'wait until all "read" operations have completed', the reader(s) need to acquire a lock. Writers then wait for that same lock to be released, and acquire it themselves to restrict other readers or writers until they've finished their update and release it.

what thread synchronisation methods can I use to achieve this behaviour?

A mutex is indeed suitable, though you will often get higher performance from a reader-writer lock (which allows concurrent readers, some also prioritorise waiting writers over further readers). Related POSIX threads functions include: pthread_rwlock_rdlock, pthread_rwlock_wrlock, pthread_rwlock_unlock etc..

To contrast the two approaches, with readers and writers using a mutex you get serialisation something like this:

THREAD   ACTIONreader1  pthread_mutex_lock(the_mutex) returns having acquired lock, and         thread starts reading datareader2  pthread_mutex_lock(the_mutex) "hangs", as blocked by reader1writer1  pthread_mutex_lock(the_mutex) hangs, as blocked by reader1reader1  pthread_mutex_unlock(the_mutex) -> releases lockNOTE: some systems guarantee reader2 will unblock before writer1, some don'treader2  blocked pthread_mutex_lock(the_mutex) returns having acquired lock,         and thread starts reading datareader1  pthread_mutex_lock(the_mutex) hangs, as blocked by reader2reader2  pthread_mutex_unlock(the_mutex) -> releases lock    writer1  blocked pthread_mutex_lock(the_mutex) returns having acquired lock,         and thread starts writing and/or reading datawriter1  pthread_mutex_unlock(the_mutex) -> releases lock    reader1  blocked pthread_mutex_lock(the_mutex) returns having acquired lock,         and thread starts reading data...etc...

With a read-write lock, it might be more like this (notice the first two readers run concurrently):

THREAD   ACTIONreader1  pthread_rwlock_rdlock(the_rwlock) returns having acquired lock, and         thread starts reading datareader2  pthread_rwlock_rdlock(the_rwlock) returns having acquired lock, and         thread starts reading datawriter1  pthread_rwlock_wrlock(the_rwlock) hangs, as blocked by reader1/2reader1  pthread_rwlock_unlock(the_rwlock) -> releases lockreader1  pthread_rwlock_rwlock(the_rwlock) hangs, as pending writerreader2  pthread_rwlock_unlock(the_rwlock) -> releases lock    writer1  blocked pthread_rwlock_wrlock(the_rwlock) returns having acquired lock,         and thread starts writing and/or reading datawriter1  pthread_rwlock_unlock(the_rwlock) -> releases lock    reader1  blocked pthread_rwlock_rwlock(the_rwlock) returns having acquired lock,         and thread starts reading data...etc...