Keywords: TestMetaData

# Concurrent Operations

The operations `count`, `find`, `insert`, and `erase` are the only operations that may be concurrently invoked on the same `concurrent_hash_map`. These operations search the table for a key-value pair that matches a given key. The `find` and `insert` methods each have two variants. One takes a `const_accessor` argument and provides read-only access to the desired key-value pair. The other takes an accessor argument and provides write access. Additionally, `insert` has a variant without any accessor.

### Caution

The concurrent operations (`count`, `find`, `insert`, and `erase`) invalidate any iterators pointing into the affected instance even with a `const` qualifier. It is unsafe to use these operations concurrently with any other operation. An exception to this rule is that `count` and `find` do not invalidate iterators if no insertions or erasures have occurred after the most recent call to method `rehash`.

### Tip

In serial code, use the `equal_range` method instead of the `find` method for lookup, since `equal_range` is faster and does not invalidate iterators.

### Tip

If the `nonconst` variant succeeds in finding the key, the consequent write access blocks any other thread from accessing the key until the accessor object is destroyed. Where possible, use the const variant to improve concurrency.

Each map operation in this section returns true if the operation succeeds, false otherwise.

### Caution

Though there can be at most one occurrence of a given key in the map, there may be other key-value pairs in flight with the same key. These arise from the semantics of the `insert` and `erase` methods. The `insert` methods can create and destroy a temporary key-value pair that is not inserted into a map. The erase methods remove a key-value pair from the map before destroying it, thus permitting another thread to construct a similar key before the old one is destroyed.

### Tip

To guarantee that only one instance of a resource exists simultaneously for a given key, use the following technique:

- To construct the resource: Obtain an `accessor` to the key in the map before constructing the resource.

- To destroy the resource: Obtain an `accessor` to the key, destroy the resource, and then erase the key using the accessor.

Below is a sketch of how this can be done.

            extern tbb::concurrent_hash_map<Key,Resource,HashCompare> Map;

        void ConstructResource( Key key ) {
               accessor acc;
               if( Map.insert(acc,key) ) {
                       // Current thread inserted key and has exclusive access.
                       ...construct the resource here...
               }
               // Implicit destruction of acc releases lock
        }

        void DestroyResource( Key key ) {
               accessor acc;
               if( Map.find(acc,key) ) {
                       // Current thread found key and has exclusive access.
                       ...destroy the resource here...
                       // Erase key using accessor.
                       Map.erase(acc);
               }
        }

The following table provides additional information on the members of this template class.
Member | Description
--- | ---
size_type count( const Key& key ) const | ### Caution This method may invalidate previously obtained iterators. In serial code, you can use `equal_range` that does not have such problems. Returns: 1 if map contains key; 0 otherwise.
bool find( const_accessor& result, const Key& key ) const | Searches table for pair with given key. If key is found, sets result to provide read-only access to the matching pair. ### Caution This method may invalidate previously obtained iterators. In serial code, you can use `equal_range` that does not have such problems. Returns: True if key was found; false if key was not found.
bool find( accessor& result, const Key& key ) | Searches table for pair with given key. If key is found, sets result to provide write access to the matching pair ### Caution This method may invalidate previously obtained iterators. In serial code, you can use `equal_range` that does not have such problems. Returns: True if key was found; false if key was not found.
bool insert( const_accessor& result, const Key& key ) | Searches table for pair with given key. If not present, inserts new `pair(key,T())` into the table. Sets `result` to provide read-only access to the matching pair. Returns True if new pair was inserted; false if key was already in the map.
bool insert( accessor& result, const Key& key ) | Searches table for pair with given key. If not present, inserts new `pair(key,T())` into the table. Sets `result` to provide write access to the matching pair. Returns: True if new pair was inserted; false if key was already in the map.
bool insert( const_accessor& result, const value_type& value ) | Searches table for pair with given key. If not present, inserts new pair copy-constructed from value into the table. Sets result to provide read-only access to the matching pair. Returns: True if new pair was inserted; false if key was already in the map.
bool insert( accessor& result, const value_type& value ) | Searches table for pair with given key. If not present, inserts new pair copy-constructed from `value` into the table. Sets `result` to provide write access to the matching pair. Returns True if new pair was inserted; false if key was already in the map.
bool insert( const value_type& value ) | Searches table for pair with given key. If not present, inserts new pair copy-constructed from `value` into the table. Returns: True if new pair was inserted; false if key was already in the map. ### Tip If you do not need to access the data after insertion, use the form of insert that does not take an accessor; it may work faster and use fewer locks.
template<typename InputIterator> void insert( InputIterator first, InputIterator last ) | For each pair `p` in the half-open interval [`first,last`), does `insert(p)`. The order of the insertions, or whether they are done concurrently, is unspecified. ### Caution The current implementation processes the insertions in order. Future implementations may do the insertions concurrently. If duplicate keys exist in [`first,last`), be careful to not depend on their insertion order.
bool erase( const Key& key ) | Searches table for pair with given key. Removes the matching pair if it exists. If there is an accessor pointing to the pair, the pair is nonetheless removed from the table but its destruction is deferred until all accessors stop pointing to it. Returns: True if pair was removed by the call; false if key was not found in the map.
bool erase( const_accessor& item_accessor ) | Requirements: `item_accessor.empty()==false` Effects Removes pair referenced by `item_accessor`. If there is another const_accessor pointing to the pair, the pair is nonetheless removed from the table but its destruction is deferred until all accessors stop pointing to it. Concurrent insertion of the same key creates a new pair in the table, which can temporarily co-exist with the one being destroyed. Returns: True if pair was removed by this thread; false if pair was removed by another thread.
bool erase( accessor& item_accessor ) | Requirements: `item_accessor.empty()==false` Effects Removes pair referenced by `item_accessor` from the table and destroys it. Concurrent insertion of the same key creates a new pair in the table, which can temporarily co-exist with the one being destroyed. Returns: True if pair was removed by this thread; false if pair was removed by another thread.

Parent topic: concurrent_hash_map Template Class