我正在C ++中开发一个LRU-cache,在多线程环境中使用boost互斥锁和锁。 该架构基于boost :: unordered_map + a lock-free-queue 插入以非阻塞模式(try_lock)工作,但删除应锁定地图并继续。 问题是很少,缓存访问死锁在删除。
·H
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());
}
}
你能解释一下我的错吗?我几乎可以肯定它在移除中是死锁,因为它是必须获取的唯一锁。
谢谢大家
编辑:我在运行mpm_prefork_module的apache模块中使用此缓存:这可能是问题吗?我应该使用boost :: interprocess而不是boost :: thread吗?