2013-06-19 51 views
2

我有以下的情況下(簡體):有沒有可能找到或創建沒有鎖定或提供未來?

/* Register objects living 
    and retrieve them on demand if the object is still alive on request. 
    The interface have to be concurrency-safe. 
*/ 
class Registry 
{ 
public: 

    void add(const std::shared_ptr<Thing>& thing) 
    { m_index.emplace_back(thing); 

    std::shared_ptr<Thing> find(ThingId id) 
    { 
     auto find_it = m_index.id(id); 
     if(find_it != end(m_index)) 
     { 
      // we can't remove the index safely (see http://software.intel.com/sites/products/documentation/doclib/tbb_sa/help/index.htm) 
      return find_it->second.lock(); // null if the object don't exist anymore 
     } 
     return nullptr; 
    } 

private: 
    tbb::concurrent_unordered_map< ThingId, std::weak_ptr<Thing> > m_index; 
}; 

// Concurrency safe too. 
class Workspace 
{ 
    Registry m_registry; 
    std::unique_ptr<Thing> make_new_thing(ThingId id); // not important 
public: 

    std::shared_ptr<Thing> find(ThingId id) { return m_registry.find(id); } 

    /* The goal here is to either retrieve the existing object, 
     or to create it. 
    */ 
    std::shared_ptr<Thing> find_or_create(ThingId id) 
    { 
     // HERE IS THE PROBLEM!!! 
     if(auto thing = m_registry.find(id)) 
      return thing; 
     return make_new_thing(); 
    } 
}; 

// Concurrency-safe too. 
class Editor 
{ 
    Workspace& m_workspace; 
    tbb::concurrent_unordered_set<std::shared_ptr<Thing>> m_things; 
public: 

    void add_target(ThingId id) 
    { 
     m_things.push(m_workspace.find_or_create(id)); 
    } 

}; 

的背景是重要的,但讓我們專注於這一部分:

std::shared_ptr<Thing> find_or_create(ThingId id) 
{ 
    if(auto thing = m_registry.find(id)) 
     return thing; 
    return make_new_thing(); 
} 

這裏,如果同時呼叫是爲這個功能製作,同時呼叫到make_new_thing ()可能會發生,如果Thing不具有相同的id,則這是有效的,但如果不具有相同的id,則不會發生。 由於concurrent_unordered_map實現,我們無法從註冊表中刪除id,所以我們無法檢查是否正在創建對象。

這一切都表明,在這種情況下,需要同步機制。然而,如果我使用類似於工作隊列的東西,那麼我將不得不提供一個當前正在鎖定的未來,但即使使用future.then(),調用者可能會等待很長時間。

我想要的是避免鎖定(使用互斥鎖),如果可能的話,沒有未來(在這種情況下)。

你看到有沒有鎖定的方法嗎?

+0

沒關係,我想我只能在調用find_or_create()時鎖定,而不是在其他情況下。 – Klaim

+0

如果有更好的解決方案,我會放棄此操作。 – Klaim

回答

0

你可以使用東西的數組或環形緩衝區,以及原子操作。內置在原子內部或處理器特定的CMPXCHG組裝操作碼中。

你會犧牲內存,並基本上創建自己的互斥和旋轉等待。

在最簡單的實現中,你的ThingId將被索引到數組中。你的「查找或創建」將是一個比較+交換原子操作,如果數組中的點是空的,你可以在已經創建的新對象中進行交換,但是如果點不是空的,你可以刪除預先創建的新對象或保存它對於下一次調用,但這需要更多的原子操作來實現對象存儲的併發。

+0

ThingId必須是一個UUID,暗示沒有辦法使用idx <=> id關係。 – Klaim

+0

@Klaim - 哈希然後按數組大小模數將是將您的UUID轉換爲循環索引的適當變換。 –

相關問題