2017-07-29 10 views
1

コインシデナが空である(ブロッキングまたはスローではなく)場合は、pop()操作でアイテムを返す必要があるロックフリーの同時データ構造のケースを考慮してください。データ構造は、潜在的に大きい可能性のあるユーザタイプTにテンプレート化されています(軽量でも、どちらの場合でも効率的なものにしたい)。 Tは少なくとも移動可能でなければならないが、コピー可能である必要はない。出力パラメータと移動セマンティクス

私は関数のシグニチャがbool DS<T>::pop(T &item)であると考えていたので、アイテムは戻り値ではなく出力パラメータとして抽出されます(代わりに成功または失敗を示すために使用されます)。しかし、どのように実際にそれを渡すのですか?下にあるバッファがあるとします。 を実行しますか?参照外のパラメータに移動するのは理にかなっていますか?欠点は、ユーザーがデフォルトで構築されたTを渡す必要があります。これは、実際のRAIIとは少し異なります。その結果は、関数が失敗した場合にリソースを実際に初期化していないオブジェクトです。

もう1つのオプションは、outパラメータを使用するのではなくstd::pair<bool, T>を返しますが、return std::make_pair(false, T)の場合は、リソースが保持されないデフォルトの構成可能なTにする必要があります。

3番目のオプションは、項目をstd::unique_ptr<T>として戻しますが、Tがポインタまたは別の軽量タイプの場合、無駄なオーバーヘッドが発生します。実際のアイテムを外部に格納したデータ構造にポインタだけを格納することはできますが、追加のデリファレンスとキャッシュミスのペナルティだけでなく、バ​​ッファに直接格納されているアイテムが自然なパディングを取り除き、スレッドが同じキャッシュラインに当たるのを防ぎます。

+5

これは、 'boost :: optional'とすぐに' std :: optional'となるものです。 – aschepler

+0

'std :: aligned_storage'を使って、オブジェクトを含むかもしれないストレージを返すことができます。これは基本的に 'std :: optional'が – KABoissonneault

答えて

1
#include <boost/optional.hpp> 
#include <string> 

template<class T> 
struct atomic_queue 
{ 
    using value_type = T; 

    auto pop() -> boost::optional<T> 
    { 
     boost::optional<T> result; 

     /* 
     * insert atomic ops here, optionally filling result 
     */ 

     return result; 
    }; 

    auto push(T&& arg) -> bool 
    { 

     /* 
     * insert atomic ops here, optionally stealing arg 
     */ 

     return true; 
    }; 

    static auto make_empty_result() { 
     return boost::optional<T>(); 
    } 

}; 

struct difficult { 
    difficult(std::string); 
    difficult() = delete; 
    difficult(difficult const&) = delete; 
    difficult& operator=(difficult const&) = delete; 
    difficult(difficult &&) = default; 
    difficult& operator=(difficult &&) = default; 
}; 

extern void spin(); 

int main() 
{ 
    atomic_queue<difficult> q; 

    auto d = difficult("arg"); 
    while(not q.push(std::move(d))) 
     spin(); 

    auto popped = q.make_empty_result(); 
    while(not (popped = q.pop())) 
     spin(); 

    auto& val = popped.get(); 
} 
関連する問題