Design Problem: Thread safety of std::map

后端 未结 5 1149
说谎
说谎 2021-01-03 14:57

I am using std::map to implement my local hash table, which will be accessed by multiple threads at the same time. I did some research and found that std::map is not thread

5条回答
  •  被撕碎了的回忆
    2021-01-03 15:54

    Binary trees are not particularly suited to Multi-Threading because the rebalancing can degenerate in a tree-wide modification. Furthermore, a global mutex will very negatively access the performance.

    I would strongly suggest using an already written thread-safe containers. For example, Intel TBB contains a concurrent_hash_map.

    If you wish to learn however, here are some hints on building a concurrent sorted associative container (I believe a full introduction to be not only out of my reach but also out of place, here).

    Reader/Writer

    Rather than a regular Mutex, you may want to use a Reader/Writer Mutex. This means parallelizing Reads, while Writes remain strictly sequential.

    Own Tree

    You can also build your own red-black or AVL tree. By augmenting the tree structure with a Reader/Writer Mutex per node. This allows you to only block part of the tree, rather than the whole structure, even when rebalancing. eg inserts with keys far enough apart can be parallel.

    Skip Lists

    Linked lists are much more amenable to concurrent manipulations, because you can easily isolate the modified zone.

    A Skip List builds on this strength, but augments the structure to provide O(log N) access by key.

    The typical way to walk a list is using the hand over hand idiom, that is, you grab the mutex of the next node before releasing the one of the current node. Skip Lists add a 2nd dimension as you can dive between two nodes, thus releasing both of them (and letting other walkers go ahead of you).

    Implementations are much simpler than for binary search trees.

    Persistent

    Another interesting piece is the idea of persistent (or semi-persistent) data-structures, often found in functional programming. Binary Search Tree are particularly amenable for it.

    The basic idea is to never change a node (or its content) once it exists. You do so by sharing a mutable head, that will point to the later version.

    • To Read: you copy the current head, then use it without worry (the information is immutable)
    • To Write: each node that you would modify in a regular tree is instead copied and the copy modified, therefore you rebuild part of the tree (up to the root) each time, and update the head to point to the new root. There are efficient ways to rebalance on descending the tree. Writes are sequential

    The main advantage is that a version of the map is always available. That is, you can always read even when another thread is performing an insert or delete. Furthermore, because read access only require a single concurrent read (when copying the root pointer), they are near lock-free, and thus have excellent performance.

    Reference counting (intrinsic) is your friend for those nodes.

    Note: copies of the tree are very cheap :)


    I do not know any implementation in C++ of either a concurrent Skip List or a concurrent Semi-Persistent Binary Search Tree.

提交回复
热议问题