boost::lock_guard ждет вечно

Я разрабатываю LRU-кеш на C++, используя буст-мьютексы и блокировки, в многопоточной среде. Архитектура основана на boost::unordered_map + lock-free-queue Вставки работают в неблокирующем режиме (try_lock), но удаления должны заблокировать карту и продолжить. Проблема в том, что очень редко, кеш-доступ тупиков при удалении.

.час

typedef boost::function<std::string ( const std::string &key )> LoaderFunction;

class ListNode;

struct CacheEntry {
    CacheEntry(std::string key="", std::string value="");
    ListNode * createLruListNode() const;
    ListNode * getLruListNode() const;
    virtual ~CacheEntry();
    const std::string key;
    const std::string value;
private:
    ListNode ** listNodePP;
};

struct ListNode {
    ListNode(const CacheEntry* entry = NULL);
    ~ListNode();
    void setCacheEntry(const CacheEntry* entry);
    const CacheEntry * getCacheEntry();
    void setDirty();

private:
    const CacheEntry * cacheEntry;
    bool dirty;
};

typedef LockFreeQueue<ListNode*> List;


typedef boost::unordered_map
        < const string               , const CacheEntry * >
Cache;

typedef Cache::iterator CacheIter;

.cpp

#include "LockFreeQueue.h"
#include <unistd.h>

using namespace std;

/* ... */

ListNode::ListNode(const CacheEntry* e2) : cacheEntry(e2) {
    dirty=false;
}

void ListNode::setCacheEntry(const CacheEntry* entry) {
    cacheEntry=entry;
}

const CacheEntry* ListNode::getCacheEntry() {
    if(dirty) {
        return NULL;
    }
    return cacheEntry;
}

void ListNode::setDirty() {
    dirty=true;
}

std::string PeachCachePartition::get(const string key) {
    CacheIter iter=cache->find(key);
    string value;
    if(iter!=cache->end()) { 
        __sync_fetch_and_add(_hits,1);
        const CacheEntry* entry=iter->second;
        value=(entry->value);

        lruList->enqueue(entry->getLruListNode());
        if(size() > max) { // removes some
            int howMany = (int) ceil((*_misses)/(*_hits))+1;
            int k=0;
            ListNode removedListNode=ListNode();
            ListNode * p=&removedListNode;
            ListNode ** pp=&p;
            while(size() > max && k<howMany) {

                if(lruList->dequeue(pp)) {
                    const CacheEntry * toBeRemoved=p->getCacheEntry();
                    if(toBeRemoved) {
                        remove(toBeRemoved->key);
                        k++;
                    }
                }


            }
        }
    } else { 
        __sync_fetch_and_add(_misses,1);
        value=loader(key);
        if(value.size()>0) {
            put(key,value);
        }
    }
    return value;
}

void PeachCachePartition::remove(const std::string &key) {
    try {
        boost::lock_guard<boost::mutex> mapLockGuard(mapMutex);
        CacheIter iter = cache->find(key);
        if(iter!=cache->end()) {
            const CacheEntry * toBeRemoved=iter->second;
            if(toBeRemoved->getLruListNode()) {
                toBeRemoved->getLruListNode()->setDirty();
            }

            delete(toBeRemoved);
            cache->erase(iter);
            __sync_sub_and_fetch(_size,1);
        }
    } catch (std::exception &e) {
        Logger::err(e.what());
    }
}


void PeachCachePartition::put(const std::string &key, std::string &value) {
    try {
        boost::unique_lock<boost::mutex> mapLockGuard(mapMutex,boost::try_to_lock);
        if(mapLockGuard.owns_lock()) {
            CacheIter iter=cache->find(key);
            const CacheEntry * entry;
            if(iter!=cache->end()) {
                entry=iter->second;
                entry->getLruListNode()->setDirty();
            } else {
                entry = new CacheEntry(key,value);
                __sync_add_and_fetch(_size,1);
                (*cache)[key] = entry;
            }

            entry->createLruListNode()->setCacheEntry(entry);

            lruList->enqueue(entry->getLruListNode());
        }
    } catch (std::exception &e) {
        Logger::err(e.what());
    }
}

Можете ли вы объяснить мне, что не так? Я почти уверен, что он заблокирован при удалении, поскольку это единственный замок, который он должен получить.

Спасибо всем

редактировать: я использую этот кеш в модуле apache, который запускает mpm_prefork_module: это может быть проблемой? Должен ли я использовать boost:: interprocess вместо boost::thread?

0 ответов

Другие вопросы по тегам