2

複数のスレッドによって読み取られ、更新されるデータがいくつかあります。読み取りと書き込みの両方がアトミックである必要があります。私はこのようにすることを考えていました:

// Values must be read and updated atomically
struct SValues
{
    double a;
    double b;
    double c;
    double d;
};

class Test
{
public:
    Test()
    {
        m_pValues = &m_values;
    }

    SValues* LockAndGet()
    {
        // Spin forver until we got ownership of the pointer
        while (true)
        {
            SValues* pValues = (SValues*)::InterlockedExchange((long*)m_pValues, 0xffffffff);
            if (pValues != (SValues*)0xffffffff)
            {
                return pValues;
            }
        }
    }

    void Unlock(SValues* pValues)
    {
        // Return the pointer so other threads can lock it
        ::InterlockedExchange((long*)m_pValues, (long)pValues);
    }

private:
    SValues* m_pValues;
    SValues m_values;
};

void TestFunc()
{
    Test test;

    SValues* pValues = test.LockAndGet();

    // Update or read values

    test.Unlock(pValues);
}

データは、読み取りと書き込みのたびにデータへのポインタを盗むことで保護されます。これにより、データはスレッドセーフになりますが、アクセスごとに2つのインターロックされた命令が必要です。読み取りと書き込みの両方がたくさんあり、読み取りと書き込みのどちらが増えるかを事前に知ることはできません。

これよりも効果的にできるでしょうか?これは読み取り時にもロックされますが、読み取りよりも書き込みが多い可能性があるため、書き込みにペナルティを課さない限り、読み取りを最適化しても意味がありません。

インターロックされた命令なしで(シーケンス番号とともに)ポインターを取得し、データをコピーしてから、シーケンス番号が変更されたかどうかを確認する方法を考えていました。変更された場合は、再試行する必要があります。ただし、これにはいくつかのメモリバリアが必要であり、速度が向上するかどうかはわかりません。

- - - 編集 - - -

みんなありがとう、素晴らしいコメント!私は実際にこのコードを実行していませんが、現在のメソッドを今日の後半にクリティカルセクションと比較しようとします(時間があれば)。私はまだ最適な解決策を探しているので、後でより高度なコメントに戻ります。再度、感謝します!

4

2 に答える 2

3

あなたが書いたのは本質的にスピンロックです。これを行う場合は、 boost::mutexなどのミューテックスを使用することもできます。本当にスピンロックが必要な場合は、独自に作成するのではなく、システムが提供するスピンロック、またはライブラリからのスピンロックを使用してください。

他の可能性には、何らかの形式のコピーオンライトを実行することが含まれます。データ構造をポインタで格納し、読み取り側でポインタを(原子的に)読み取るだけです。次に、書き込み側で新しいインスタンスを作成し(必要に応じて古いデータをコピーします)、ポインターをアトミックに交換します。書き込みに古い値が必要で、複数のライターが存在する場合は、読み取り後に値が変更されていないことを確認するために比較交換ループを実行する必要があります(ABA問題に注意してください)。作家。これを行う場合は、メモリの管理方法に注意する必要があります---データを参照しているスレッドがない場合(以前はそうではありません)にデータのインスタンスを再利用する方法が必要です。

于 2010-07-29T07:43:07.867 に答える
3

これを解決するには、特にミューテックスやロックメカニズムを使用せずに、いくつかの方法があります。問題は、システムの制約が何であるかわからないことです。

アトミック操作は、C++のコンパイラーによって頻繁に移動されるものであることを忘れないでください。

一般的に私はこのような問題を解決します:

書き込みスレッドごとに1つの単一のプロデューサー-単一のコンシューマーを持つことによる複数のプロデューサー-単一のコンシューマー。各スレッドは独自のキューに書き込みます。生成されたデータを収集し、それを単一のコンシューマー、複数のリーダーのデータストレージに格納する単一のコンシューマースレッド。このための実装は多くの作業であり、タイムクリティカルなアプリケーションを実行していて、このソリューションに取り組む時間がある場合にのみ推奨されます。

実装はプラットフォーム固有であるため、これについて読むべきことがもっとあります。

windows / xbox360でのアトミックなどの操作:http://msdn.microsoft.com/en-us/library/ee418650(VS.85) .aspx

ロックなしのマルチスレッドシングルプロデューサーシングルコンシューマー:http:
//www.codeproject.com/KB/threads/LockFree.aspx#heading0005

「揮発性」とは実際には何であり、次の目的で使用できます:
http ://www.drdobbs.com/cpp/212701484

ハーブサッターは、この種のコードを書くことの危険性を思い出させる良い記事を書いています: http ://www.drdobbs.com/cpp/210600279; jsessionid = ZSUN3G3VXJM0BQE1GHRSKHWATMY32JVN?pgno = 2

于 2010-07-29T07:48:16.990 に答える