Boost logo

Boost :

Subject: Re: [boost] GSOC 2015 : Project on Concurrent Hash Tables
From: Amarnath V A (me_at_[hidden])
Date: 2015-03-06 23:36:28


On Fri, Mar 6, 2015 at 7:00 PM, Niall Douglas <s_sourceforge_at_[hidden]> wrote:
>
> Move construction of the map != move construction of the buckets.
>

Okay. I am trying to achieve move construction in the same spirit. And
I am piggybacking on Niall's implementation of _rehash().

      concurrent_unordered_map(concurrent_unordered_map &&old_map)
BOOST_NOEXCEPT :
          _hasher(std::move(old_map._hasher)),
          _key_equal(std::move(old_map._key_equal)),
          _allocator(std::move(old_map._allocator)),
          _max_load_factor(std::move(old_map._max_load_factor)),
          _min_bucket_capacity(std::move(old_map._min_bucket_capacity))
      {
        typedef decltype(_rehash_lock) rehash_lock_t;
        lock_guard<rehash_lock_t> guard(old_map._rehash_lock,
adopt_lock_t());
        buckets_type
&old_buckets=*(old_map._buckets.load(memory_order_consume));
        size_t n = old_buckets.size();
        if(n)
        {
          // Lock all existing buckets
          for(auto &b : old_buckets)
            b.lock.lock();
        }

        buckets_type *tempbuckets=new buckets_type(13);
        auto untempbuckets=undoer([&tempbuckets]{ delete tempbuckets; });

        buckets_type *buckets=new buckets_type(n);

        // Swap old buckets with new buckets
        tempbuckets=old_map._buckets.exchange(tempbuckets,
memory_order_acq_rel);
        // Tell all threads using old buckets to start reloading the bucket list
        for(auto &b : *tempbuckets)
          b.lock.store(2);

        // Simply move the old buckets into new buckets as-is
        for(auto obit=tempbuckets->begin(), bit=buckets->begin();
obit!=tempbuckets->end(); ++obit, ++bit)
        {
          auto &ob=*obit;
          auto &b=*bit;
          if(ob.count.load(memory_order_relaxed))
          {
            b.items=std::move(ob.items);
            b.count.store(ob.count.load(memory_order_consume),
memory_order_release);
            ob.count.store(0, memory_order_release);
          }
        }

Is this the right direction?

>
> Old buckets go into a fixed size ring buffer, and get deleted
> eventually.
>

I couldn't really figure out where the ring buffer is which you are
mentioning here. What am I missing?

And another question, when I use the above implementation of move
constructor and later call empty() on the newly created object, I land
in a segfault. I see that the empy() checks on if the lock state is 2
and continues to check the next bucket. But, I think here I have all
buckets set to lock state 2. Why did the swap I performed with the
tempbuckets and oldmap._buckets not help me? Any pointers will be
really helpful.

Thanks,
Amarnath


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk