9

競合状態の定義: 競合状態または競合ハザードは、システムまたはプロセスの欠陥であり、プロセスの出力または結果が、他のイベントのシーケンスまたはタイミングに予期せず決定的に依存します。

次の擬似コードを検討してください。

    Global variable i initialized to 6;
    Thread 1: 
        acquire(lock l)
        increment global variable i, i.e. i++;

    Thread 2: 
       acquire(lock l)
       double the value of global var i, i.e.: i*=2;

T1 が最初にロック l を取得し、T2 が 2 番目にロック l を取得した場合、i の値は 14 になります。一方、T2 が最初にロック l を取得し、T1 が 2 番目にロック l を取得した場合、i の値は 13 になります。

それで、これは競合状態ですか?

更新: 多数のコメントと回答の後、意見はまだ分かれています。私の意見は、「はい、これは競合状態です」というカテゴリです。実際、別の質問で、この例を競合状態の状況として示しました。同時に、「いいえ、これは競合状態ではありません」というカテゴリでいくつかの興味深いコメントも読みました。問題を見る視点/レベルに応じて、これが競合状態であるかどうかにかかわらず、解決して結論づけると思います。ただし、興味深い回答/コメントをまだ待っています。

4

5 に答える 5

8

アルゴリズムの例に競合状態があるかどうかは、アルゴリズムが何をすることが期待されているかに依存すると思います。

の変更にデータ競合はありませんi。これらのアクセスはシリアル化され、相互にアトミックに発生します。

ただし、乗算の前にインクリメントが発生することがアルゴリズムの正確性にとって重要な場合 (またはその逆)、競合が発生し、アルゴリズムの実行を同期させるために他の手段を使用する必要があります。アルゴリズムが複雑な計算方法であると想定される場合i * 2 + 1(スレッドを使用して計算を実行するのはばかげているかもしれません)、競合状態が発生します。

次のプログラム スニペットを検討してください。

int data;

pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER;

void* wait_for_data(void*)
{
    pthread_mutex_lock( &mux);
    pthread_cond_wait( &condvar, &mux);

    puts("got the data: %d\n", data);

    pthread_mutex_unlock( &mux);

    return 0;
}


void* set_data(void*)
{
    pthread_mutex_lock( &mux);

    data = 42;

    pthread_cond_signal( &condvar);

    pthread_mutex_unlock( &mux);

    return 0;
}

両方のスレッドは本質的に完全に相互に排他的であり、データ競合はありません。ただし、条件変数を待機するset_data()前にシグナルを送ると、決して完了しません。ほとんどの人は、条件変数の不適切な使用による競合状態と呼ぶと思います。wait_for_data()wait_for_data()

于 2012-08-17T15:38:26.703 に答える
2

いいえ、ちがいます。iに読み書きする前にロックするからです。したがって、例の読み取りと書き込みは常に一貫しています。もちろん、各操作の後にロックを解除する必要がありますが、疑似コードにそれを追加するのを忘れただけだと思います。

于 2012-08-17T13:59:50.350 に答える
2

いいえ、これは予想される実行シーケンスの 1 つです。競合はある種のロックでカウンターを保護しないため、ロード、変更、ストアのサイクルを同時に実行できます。

編集 0:

@Gheorghe、共同銀行口座の例を考えてみてください.2人の人が同時に異なる銀行のオフィスでお金を引き出しています. 各場所の店員は、口座残高を確認し、現金を出し、新しい残高を書き留める必要があります。これが残高に関して「アトミック」でない場合、つまり、この操作中にアカウントが「ロック」されていない場合、銀行にあるよりも多くのお金を 2 人の間で受け取ることになる可能性があります。銀行はそれを好まない。

しかし、操作中にアカウントがロックされた場合、出力はタイミングに依存しますか? はい、絶対に - 合計は変わりませんが、2 つの間の分割は異なる可能性があります。

重要なのは、保護された価値の一貫性です。この 2 人がどのような順序で何回裏からお金を受け取っても、最初に持っていた以上のものを得ることはありません。

于 2012-08-17T14:00:24.530 に答える
1

注:質問はJavaメモリモデルに関する以前の議論から生じたものであるため、Javaの観点から回答します。

「競合状態」の定義については多くの混乱があるようです。そのため、さまざまな回答が得られています。

「データ競合」を意味する場合、Javaのコンテキストで有効な定義は1つだけであり、Java言語仕様17.4.5で指定されています。

プログラムに、発生前の関係によって順序付けられていない2つの競合するアクセス(§17.4.1)が含まれている場合、データ競合が含まれていると言われます。

競合するアクセスは17.4.1で定義されています。

同じ変数への2つのアクセス(読み取りまたは書き込み)は、アクセスの少なくとも1つが書き込みである場合、競合していると言われます。

あなたの場合、コードには17.4.5で定義されているHappeen -Before関係が含まれています。

モニターのロック解除が発生します-そのモニターの後続のすべてのロックの前に。

したがって、Javaコンテキストでは、コードにデータの競合はありません。そうでないと言う人は、Java以外の定義を使用しています。

他の人は、2つのコードのいずれかが最初に実行できるという意味で「一般的な人種」についてコメントしていますが、それはアルゴリズムの質問です。コードは並列化可能で問題ではないか、そうでないので順次実行する必要があります。しかし、これはバグであり、データの競合ではありません。

于 2012-08-18T08:18:50.707 に答える
-1

はい。定義上、そうです。また、変動するボラティリティに問題があります。この場合、どのスレッドがどのレジスタにメモリから変数をロードし、それをメモリに保存するかは保証されません。したがって、場合によっては、1つのスレッドが古い値を取得する可能性があります。多くの言語では、どういうわけか、常にクリーンなコピーをフェッチするようにする必要があります。(Java volatileの場合)

http://www.freebsd.org/doc/en/books/developers-handbook/secure-race-conditions.html

それも良い定義だと思います。

読書:http ://dl.acm.org/citation.cfm?id = 130623

「2つの異なる概念が暗黙的に考慮されています。1つは決定論的であることが意図されたプログラム(一般的な競合と呼ばれます)に関するもので、もう1つはクリティカルセクションを含む非決定論的なプログラム(データ競合と呼ばれる)に関するものです。」

ですから、そのプログラムが常に同じ結果を生むと仮定すれば、それは「一般的なレース」だと言えます。そうでなければ、あなたは非常に奇妙なデザインを持っています。

于 2012-08-17T13:58:34.737 に答える