5

これを行うのは安全ですか?

int fd;

void thread_main()
{
    char buf[M];
    ssize_t r = read(fd, buf, M);
    assert(r == M);
    ...
}

int main()
{
    fd = open("/dev/urandom", O_RDONLY);

    for (int i = 0; i < N; i++)
         start_thread(i);

    for (int i = 0; i < N; i++)
         join_thread(i);
}

つまり、メインスレッドから実行した後、異なるスレッドコンテキストから同期を解除しても安全open(2)ですか?"/dev/urandom"read(2)

どのような状況でアサートが発生しますか?2つのスレッドが同じデータを取得することはありますか?何がうまくいかない可能性がありますか?

4

2 に答える 2

6

コードがクラッシュしない限り、コードは安全です。はassertトリガーされません。2つのスレッドが同じランダムデータを取得することはありません(ほとんどありませんが、偶然に同じである2つの「異なる」ランダムシーケンスを取得する可能性はありますしたがって、これを100%保証することはできません)。

/dev/urandom読み取ろうとするよりも少ないバイトをブロックまたは返すことはありませんが、十分な量を読み取ると、最終的にエントロピーが不足するため、乱数の品質は最終的にわずかに低下します。通常、これで十分であり、それが発生するまでにはしばらく時間がかかりますが、注意する必要があります(ほとんどの人は気にする必要はありませんが、何をするかによっては受け入れられない場合があります) 。

read/writeはスレッドセーフであり(データがクラッシュしたり破損したり、記述子が未定義の状態のままになったりすることはありません)、この特殊なケースでは、異なるプロセスとの間の読み取り/書き込み間でバイトを混合/分割しないでください。ただし、一般的に、read/write はこれを保証するものではありません。一部のデバイスでは、同時読み取り/書き込みでデータが混ざり合う場合があります

ただし、他のランダムビットを取得し、他の誰かがその間にいくつかの(異なる)ビットを取得した場合、ランダムビットはまだランダムであるため、問題にはなりません。
それがあなたにとって問題であると思うなら、厳密な原子性readv保証するものを使用してください(混合/混合はありません)。readv/に出入りするものはすべてwritev、常に1つの原子単位として処理されます(rodrigoが指摘しているように、パイプのサイズを超える場合を除きます)。PIPE_BUF

于 2012-09-03T10:48:36.973 に答える
2

読み取りは、システムコールであるという意味でスレッドセーフであり、複数のスレッドから複数の読み取りを行う場合、各読み取りはシリアルに処理されます。つまり、スレッドAが数バイトを読み取り、スレッドBが数バイトを読み取り、スレッドAがさらにバイトを読み取るのではなく、スレッドAがMバイトを読み取り、スレッドBが次のMバイトを読み取るというようになります。

書き込みについても同じことが言えます。

複数のスレッドが読み取りと書き込みを行う場合の通常の問題は、一度に1文字ずつ読み取り/書き込みを行うことが多いため、入力の行き先と出力の出所を混同する機会がたくさんあることです。読み取り/書き込みの上に存在する言語ランタイムライブラリによって追加されます

于 2012-09-03T09:31:51.163 に答える