簡體   English   中英

C ++中的多線程read-many,write-seldom array / vector迭代

[英]Multithreaded read-many, write-seldom array/vector iteration in C++

我需要以只讀方式幾乎不斷迭代一系列結構,但是對於每1M +讀取,其中一個線程可能附加一個項目。 我認為使用互斥鎖在這里會有點過分,我也會在某處讀到r / w鎖具有讀者自身的缺點。

我正在考慮在std :: vector上使用reserve(),但是這個答案使用索引安全方式迭代STL容器以避免使用鎖? 似乎無效。

什么方式的任何想法可能是最快的? 最重要的是讓讀者能夠以盡可能少的爭用快速有效地進行迭代。 寫入操作不是時間敏感的。

更新:我的另一個用例是“列表”可能包含指針而不是結構。 即,std :: vector。 相同的要求適用。

更新2:假設的例子

全球可訪問:

typedef std::vector<MyClass*> Vector;
Vector v;
v.reserve(50);

讀者線程1-10 :(這些運行一直運行)

.
.
int total = 0;
for (Vector::const_iterator it = v.begin(); it != v.end(); ++it)
{
   MyClass* ptr = *it;
   total += ptr->getTotal();
}
// do something with total
.
.

作家帖子11-15:

MyClass* ptr = new MyClass();
v.push_back(ptr);

這基本上就是這里發生的事情。 線程1-15可以同時運行,盡管通常只有1-2個讀取線程和1-2個寫入器線程。

我認為可以在這里工作的是vector自己實現,如下所示:

template <typename T> class Vector
{
// constructor will be needed of course
public:
    std::shared_ptr<const std::vector<T> > getVector()
        { return mVector; }
    void push_back(const T&);

private:
    std::shared_ptr<std::vector<T> > mVector;
};

然后,每當讀者需要訪問特定的Vector ,他們應該調用getVector()保持返回的shared_ptr直到讀完為止。

但是作者應該總是使用Vectorpush_back來增加新的價值。 然后,此push_back應檢查mVector.size() == mVector.capacity() ,如果為true,則分配 vector並將其分配給mVector 就像是:

template <typename T> Vector<T>::push_back(const T& t)
{
    if (mVector->size() == mVector->capacity())
    {
        // make certain here that new_size > old_size
        std::vector<T> vec = new std::vector<T> (mVector->size() * SIZE_MULTIPLIER);

        std::copy(mVector->begin(), mVector->end(), vec->begin());
        mVector.reset(vec);
    }
// put 't' into 'mVector'. 'mVector' is guaranteed not to reallocate now.
}

這里的想法受到RCU(讀取 - 復制 - 更新)算法的啟發。 如果存儲空間耗盡,只要至少有一個讀取器訪問舊存儲,新存儲不應使舊存儲無效。 但是,應該分配新存儲,並且任何讀者在分配之后都應該能夠看到它。 一旦沒有人再使用舊存儲應該被解除分配(所有讀者都已完成)。

由於大多數硬件架構提供了一些原子遞增和遞減的方法,我認為shared_ptr (以及Vector )將能夠完全無鎖地運行。

但是,這種方法的一個缺點是,根據讀者持有shared_ptr時間長短,您最終可能會獲得data多個副本。

PS:希望我在代碼中沒有犯過太多令人尷尬的錯誤:-)

...在std :: vector上使用reserve()...

只有在可以保證向量永遠不需要增長的情況下,這才有用。 你已經說明了如果物品沒有超出限制的數字,那么你就無法保證。

盡管存在鏈接問題,但您可以設想使用std::vector來為您管理內存,但是需要額外的邏輯層來解決已接受答案中確定的問題。


實際答案是:最快的做法是最小化同步量。 最小同步取決於您未指定的代碼和用法的詳細信息。


例如,我使用固定大小的塊的鏈表列出了一個解決方案。 這意味着您的常見用例應該與數組遍歷一樣高效,但是您可以在不重新分配的情況下動態增長。

但是,實施結果對以下問題很敏感:

  • 是否需要刪除項目
    • 每當他們被閱讀?
    • 只從前面或從其他地方?
  • 是否要讓讀者忙 - 等待容器是空的
    • 這是否應該使用某種退避
  • 需要什么程度的一致性?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM