1

リソースを書き込むスレッドと読み取るスレッドがありますが、pthread_rwlock によって多くのコンテキスト スイッチが発生します。そこで回避方法を考えます。しかし、それが安全かどうかはわかりません。

これはコードです:

sig_atomic_t slot = 0;

struct resource {
    sig_atomic_t in_use;  /*Counter,if in_use, not zero*/
    .....
} xxx[2];

int read_thread()
{
    i = slot; /*avoid slot changes in process */
    xxx[i].in_use++;
    read(xxx[i]);
    xxx[i].in_use--;
}

int write_thread()
{
    mutex_lock;  /*mutex between write threads */

    if (slot == 0) {
    while(xxx[1].in_use != 0);  /*wait last read thread in slot 1*/
    clear(xxx[1]);
    write(xxx[1]);
    slot = 1;
    } else if (slot == 1) {
    while(xxx[0].in_use != 0);
    clear(xxx[0]);
    write(xxx[0]);
    slot = 0;
    }

    mutex_unlock;
}

それはうまくいきますか?コストは、ストレージの 2 倍とアトミック変数の 3 倍です。どうもありがとう!

4

2 に答える 2

1

あなたのアルゴリズムはロックフリーではありません。ライターはスピン ロックを使用します。

ダブルバッファリングとスピンロックは本当に必要ですか? (slot ^ 1)代わりに、書き込みスロットとslot読み取りスロットとして使用できますか? 書き込み後、ライターは の値をアトミックに変更し、slotその書き込みを「公開」します。この方法で同じスロットを何度も連続して読み取ることができますが、それが必要なセマンティクスでない場合は、キューを使用する必要があります。

ところで、asig_atomic_tは複数のスレッドに必要なタイプの原子性を提供しません。少なくとも、 として宣言slotvolatile sig_atomic_t、読み取りと書き込みの際にメモリ バリアを使用する必要があります。

于 2012-06-29T14:45:01.377 に答える
0

あなたの戦略は、ライターがリーダーが読んでいるものとは異なるスロットに書き込むようにすることです。そして、書き込みが完了した後、読み取りスロット番号を切り替えています。ただし、レースがあります。

slot    reader             writer1            writer2
----    ------             -------            -------
0                          mutex_lock
        i = 0
                           ... slot=1
1                          mutex_unlock       mutex_lock
                                              ... clear(xxx[0])
        xxx[0].in_use++
        read(xxx[0])                          write(xxx[0])

ただし、一般的に、この戦略はライターの飢餓につながる可能性があります(つまり、ライターは永遠にスピンする可能性があります)。

ただし、それを許容する場合は、へxxx[]の2つのポインタの配列にする方が安全resourceです。リーダーが常にから読み取りxxx[0]、ライターがの更新を争うようにしますxxx[1]。ライターが更新を終了すると、CASonとxxx[1]を使用します。xxx[0]xxx[1]

struct resource {
    sig_atomic_t in_use;  /*Counter,if in_use, not zero*/
    sig_atomic_t writer;
    .....
} *xxx[2];

void read_thread()
{
    resource *p = xxx[0];
    p->in_use++;
    while (p->writer) {
        p->in_use--;
        p = xxx[0];
        p->in_use++;
    }
    read(*p);
    p->in_use--;
}

void write_thread()
{
    resource *p;
    mutex_lock;  /*mutex between write threads */
    xxx[1]->writer = 1;

    while(xxx[1]->in_use != 0);  /*wait last read thread in slot 1*/
    clear(xxx[1]);
    write(xxx[1]);
    xxx[1] = CAS(&xxx[0], p = xxx[0], xxx[1]);
    assert(p == xxx[1]);

    xxx[0]->writer = 0;
    mutex_unlock;
}

ライターの枯渇を回避したいが、スピンロックのパフォーマンスが必要な場合は、ミューテックスロックの代わりにスピンロックを使用して独自のリーダー/ライターロックを実装することを検討しています。「読み取り/書き込みスピンロックの実装」をグーグルで検索したところ、このページが興味深い読み物であることがわかりました。

于 2012-06-28T03:01:17.583 に答える