线程安全查找表

// thread_safe_lookup_table.h

#ifndef THREAD_SAFE_LOOKUP_TABLE_H
#define THREAD_SAFE_LOOKUP_TABLE_H

#include <atomic>
#include <vector>
#include <string>
#include <sstream>
#include <list>
#include <algorithm>
#include <memory>
#include <mutex>
#include <iostream>

static const unsigned kDefaultBucketNumber = 19;

template<typename KeyType,typename ValueType, typename HashType=std::hash<KeyType>>
class ThreadSafeLookupTable {
    public:
        static const int kStatusInit = 0x1;
        static const int kStatusSwapping = 0x2;
        static const int kStatusRestoreAfterSwapped = 0x4;
        static const int kStatusDeleteAfterSwapped = 0x8;
        static const int kStatusAll = 0x8000-1;

        static const int kIndexKey = 0;
        static const int kIndexValue = 1;
        static const int kIndexStatus = 2;

        using KeyTypeP = std::shared_ptr<KeyType>;
        using ValueTypeP = std::shared_ptr<ValueType>;
        using AtomicIntP = std::shared_ptr<std::atomic<int>>;
        using BucketValueType = std::tuple<KeyTypeP,ValueTypeP,AtomicIntP>;
        using BucketValueTypeP = std::shared_ptr<BucketValueType>;

    private:
        class BucketType {
            private:
                using bucketDataType = std::list<BucketValueTypeP>;
                using bucketIterator = typename bucketDataType::iterator;

                bucketDataType data_;
                mutable std::mutex mutex_;

                bucketIterator findIter(KeyTypeP& keyP, int status=kStatusAll) {
                    return std::find_if(data_.begin(), data_.end(), 
                            [&](BucketValueTypeP& one){
                            KeyTypeP& kP = std::get<kIndexKey>(*one);
                            return (kP==keyP || *kP==*keyP) && ((*(std::get<kIndexStatus>(*one)) & status) != 0);
                            });
                }

            public:
                BucketValueTypeP findItem(KeyTypeP& keyP, int status) {
                    std::lock_guard<std::mutex> lock(mutex_);
                    bucketIterator iter = findIter(keyP, status);
                    return (iter == data_.end())? BucketValueTypeP(): *iter;
                }

                bool add(KeyTypeP& keyP, ValueTypeP& valueP, int status) {
                    std::lock_guard<std::mutex> lock(mutex_);
                    bucketIterator iter = findIter(keyP);
                    if (iter != data_.end()) {
                        //std::cout << "already exist!" << std::endl;
                        return false;
                    }
                    auto status_p = std::make_shared<std::atomic<int>>(status);
                    BucketValueType one_tuple = std::make_tuple(std::move(keyP), std::move(valueP), std::move(status_p));

                    auto one_tuple_p = std::make_shared<BucketValueType>(std::move(one_tuple));
                    data_.push_back(one_tuple_p);
                    return true;
                }

                void del(KeyTypeP& keyP) {
                    std::lock_guard<std::mutex> lock(mutex_);
                    bucketIterator iter = findIter(keyP);
                    if (iter != data_.end()) {
                        data_.erase(iter);
                    }
                }

                BucketValueTypeP findItemAndChangeStatus(KeyTypeP& keyP, int in_status, int out_status) {
                    std::lock_guard<std::mutex> lock(mutex_);
                    bucketIterator iter = findIter(keyP, in_status);
                    if (iter == data_.end()) {
                        BucketValueTypeP();
                    } else {
                        auto& sp = std::get<kIndexStatus>(**iter);
                        *sp = out_status;
                        return *iter;
                    }
                }

                std::string debug_info() {
                    std::lock_guard<std::mutex> lock(mutex_);
                    std::ostringstream oss;
                    oss << "->";
                    for (auto it = data_.begin(); it != data_.end(); ++it) {
                        BucketValueType& one = **it;
                        oss << " [" << *std::get<kIndexKey>(one)
                            << "," << *std::get<kIndexValue>(one)
                            << "," << *std::get<kIndexStatus>(one)
                            << "] ->";
                    }
                    oss << " [tail]";
                    return oss.str();
                }
        };

        using BucketTypeP = std::shared_ptr<BucketType>;

        std::vector<BucketTypeP> buckets_;
        HashType hasher_;

        BucketTypeP getBucket(KeyTypeP& keyP) {
            std::size_t const bucket_index = hasher_(*keyP) % buckets_.size();
            return buckets_[bucket_index];
        }

    public:
        ThreadSafeLookupTable(const unsigned bucket_num=kDefaultBucketNumber, const HashType& hasher=HashType()):
                buckets_(bucket_num), hasher_(hasher) {
            for(unsigned i = 0; i < bucket_num; ++i) {
                buckets_[i].reset(new BucketType);
            }
        }
        ThreadSafeLookupTable(const ThreadSafeLookupTable& other) = delete;
        ThreadSafeLookupTable& operator=(const ThreadSafeLookupTable& other) = delete;

        bool add(KeyTypeP& keyP, ValueTypeP& valueP, int status=kStatusInit) {
            return getBucket(keyP)->add(keyP, valueP, status);
        }

        bool add(KeyType key, ValueType value, int status=kStatusInit) {
            auto kp = std::make_shared<KeyType>(std::move(key));
            auto vp = std::make_shared<ValueType>(std::move(value));
            return add(kp, vp, status);
        }

        void del(KeyTypeP keyP) {
            return getBucket(keyP)->del(keyP);
        }

        void del(KeyType key) {
            del(std::make_shared<KeyType>(std::move(key)));
        }

        BucketValueTypeP findItem(KeyTypeP keyP, int status=kStatusAll) {
            return getBucket(keyP)->findItem(keyP, status);
        }

        BucketValueTypeP findItem(KeyType key, int status=kStatusAll) {
            return findItem(std::make_shared<KeyType>(std::move(key)), status);
        }

        BucketValueTypeP findItemAndChangeStatus(KeyTypeP keyP, int in_status, int out_status) {
            return getBucket(keyP)->findItemAndChangeStatus(keyP, in_status, out_status);
        }

        BucketValueTypeP findItemAndChangeStatus(KeyType key, int in_status, int out_status) {
            return findItemAndChangeStatus(std::make_shared<KeyType>(std::move(key)), in_status, out_status);
        }

        std::string debug_info() {
            std::ostringstream oss;
            for (int i = 0; i < buckets_.size(); ++i) {
                oss << "[" << i << "] " << buckets_[i]->debug_info();
                if (i < buckets_.size() - 1) {
                    oss << std::endl;
                }
            }
            return oss.str();
        }
};


#endif /* THREAD_SAFE_LOOKUP_TABLE_H */

// test.cpp

#include "thread_safe_lookup_table.h"
#include <iostream>
using namespace std;

int main() {
    using KeyType = string;
    using ValueType = string;

    using KeyTypeP = std::shared_ptr<KeyType>;
    using ValueTypeP = std::shared_ptr<ValueType>;
    using AtomicIntP = std::shared_ptr<std::atomic<int>>;
    using BucketValueType = std::tuple<KeyTypeP,ValueTypeP,AtomicIntP>;
    using BucketValueTypeP = std::shared_ptr<BucketValueType>;

    ThreadSafeLookupTable<KeyType, ValueType> myTable;
    myTable.add("000", "bba");
    myTable.add("001", "bbb");
    myTable.add("002", "bbc");
    myTable.add("003", "bbc");
    myTable.add("004", "bbc");
    myTable.add("005", "bbc");
    std::cout << myTable.debug_info() << std::endl;

    myTable.del("003");
    cout << "del 003 -----------------" << endl;
    std::cout << myTable.debug_info() << std::endl;

    cout << "add 005 -----------------" << endl;
    myTable.add("005", "bb5");
    std::cout << myTable.debug_info() << std::endl;

    cout << "change 005 -----------------" << endl;
    BucketValueTypeP item = myTable.findItem("005");
    auto& kp = std::get<0>(*item);
    auto& vp = std::get<1>(*item);
    auto& sp = std::get<2>(*item);
    vp = make_shared<KeyType>("hehe");
    *sp = 33;
    std::cout << myTable.debug_info() << std::endl;

    cout << "findItemAndChangeStatus 002 -----------------" << endl;
    item = myTable.findItemAndChangeStatus("002", 1, 999);
    std::cout << myTable.debug_info() << std::endl;

    return 0;
}
$ g++ test.cpp -o test && ./test
[0] -> [tail]
[1] -> [003,bbc,1] -> [tail]
[2] -> [004,bbc,1] -> [tail]
[3] -> [tail]
[4] -> [tail]
[5] -> [tail]
[6] -> [001,bbb,1] -> [002,bbc,1] -> [tail]
[7] -> [tail]
[8] -> [tail]
[9] -> [tail]
[10] -> [tail]
[11] -> [tail]
[12] -> [tail]
[13] -> [tail]
[14] -> [005,bbc,1] -> [tail]
[15] -> [tail]
[16] -> [tail]
[17] -> [000,bba,1] -> [tail]
[18] -> [tail]
del 003 -----------------
[0] -> [tail]
。。。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值