0

重複の可能性:
fork()と出力

実行することによって:

#include<stdio.h>
int main()
{
    fork();
    printf("b");
    if (fork() == 0) {
        write(1, "a", 1);
    }else{
        write(1, "c", 1);
    }
    return 0;
}

私は得たcbcabbab、誰かが私に出力を説明できますか?そして、可能であれば、実行中の手順を段階的に確認するためのツールはありますか?

4

3 に答える 3

2

簡単な答え:バッファリングされたコードとバッファリングされていないコードを混在させないでください。

長い答え:次のコマンドを使用して、ソースコードのバリアントをテストしましょう。

$ rm dump
$ for X in 0 1 2 3 4 5 6 7 8 9; do for Y in 0 1 2 3 4 5 6 7 8 9; do for Z in 0 1 2 3 4 5 6 7 8 9; do echo `./program` >> dump; done; done; done
$ sort -u dump

これはprogram1000回実行され、返されたすべての一意の出力を一覧表示します。

バッファリングwriteされたバージョン:(fwriteまたはprintf)に置き換えます

#include <unistd.h>
#include <stdio.h>

int main()
{
    fork();
    printf("b");
    if (fork() == 0) {
        fwrite("a", 1, 1, stdout);
    }else{
        fwrite("c", 1, 1, stdout);
    }
    return 0;
}

これにより、非常に規則的な出力パターンが得られます。実際、可能な出力は6つだけです。

bababcbc
babcbabc
babcbcba
bcbababc
bcbabcba
bcbcbaba

何が起こっている?

  1. 最初のフォークの後、WとYの2つのプロセスがあります。
  2. どちらのプロセスもストリームに手紙"b"を書きます。stdoutストリームはデフォルトでバッファリングされるため、。
  3. 2番目のフォークの後、WとX、YとZの4つのプロセスがあります。WとXのstdoutストリームは同じ状態であるため、同じバッファーに。だけが含まれ"b"ます。YとZについても同じことが言えます。
  4. stdout4つのプロセスすべてが、ストリームに別の文字を書き込みます。
  5. 戻った後main、Cランタイムが引き継ぎます。すべてのプロセスは、のバッファを含むバッファをフラッシュしますstdout

printfバッファリングされていないバージョン:次のように置き換えますwrite

#include <unistd.h>

int main()
{
    fork();
    write(1, "b", 1);
    if (fork() == 0) {
        write(1, "a", 1);
    }else{
        write(1, "c", 1);
    }
    return 0;
}

可能な出力はもう少し変化しますが、並行性を考えると、それでもかなり理解できます。

bbacca
bbcaac
bbcaca
bbccaa
bcabca
bcbaca

これはおそらくあなたが期待した出力です。

混合バージョン(あなたのもの)

あなたのコードは、前の2つのバリアントよりもはるかに多くの結果をもたらします。

cabbacbb
cabbcabb
cabbcbab
cabcabbb
cabcbabb
cabcbbab
... etc ...

これは、write呼び出しがすぐに出力を生成するためですが、バッファリングされたものは、もちろん、呼び出し"b"の各プロセスが終了したときにのみ出力されます。完全にバッファリングされたバージョンと同様に、すべてのプロセスがバッファにそれを持っているので、4つが表示されることになります。write"b"stdout

于 2013-02-01T15:00:18.393 に答える
1

もう一度実行してみてください。おそらく別の出力が得られます。

手順を段階的に確認するためのツールについてはstrace -f、少し役立つと思います。

$ strace -f ./weirdfork
execve("./weirdfork", ["./weirdfork"], [/* 35 vars */]) = 0
... uninteresting boiler plate removed ...
clone(Process 8581 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe1c7d0b9d0) = 8581
[pid  8580] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
[pid  8581] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
[pid  8580] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...>
[pid  8581] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...>
[pid  8580] <... mmap resumed> )        = 0x7fe1c7d22000
[pid  8581] <... mmap resumed> )        = 0x7fe1c7d22000
[pid  8581] clone( <unfinished ...>
[pid  8580] clone(Process 8582 attached
 <unfinished ...>
[pid  8581] <... clone resumed> child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe1c7d0b9d0) = 8582
Process 8583 attached
[pid  8580] <... clone resumed> child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fe1c7d0b9d0) = 8583
[pid  8580] write(1, "c", 1 <unfinished ...>
[pid  8581] write(1, "c", 1cc)            = 1
[pid  8580] <... write resumed> )       = 1
[pid  8581] write(1, "b", 1b <unfinished ...>
[pid  8580] write(1, "b", 1 <unfinished ...>
[pid  8581] <... write resumed> )       = 1
b[pid  8581] exit_group(0)               = ?
Process 8581 detached
[pid  8580] <... write resumed> )       = 1
[pid  8580] exit_group(0)               = ?
[pid  8583] write(1, "a", 1 <unfinished ...>
[pid  8582] write(1, "a", 1a)            = 1
a[pid  8582] write(1, "b", 1 <unfinished ...>
[pid  8583] <... write resumed> )       = 1
[pid  8583] write(1, "b", 1b)            = 1
[pid  8583] exit_group(0)               = ?
Process 8583 detached
b<... write resumed> )                   = 1
exit_group(0)                           = ?
Process 8582 detached
于 2013-02-01T13:40:51.507 に答える
0

フォークされたプロセスを同期するコードを特に追加しない限り、それらは完全に独立して実行されるため、出力の順序は完全に「ランダム」です。プロセスのスケジューリングによって、次に実行するユーザーが決まります。これは、システムにあるプロセッサコアの数、他に何が実行されているか、現在実行されている各プロセスが実行されている時間によって異なります。

リンクで説明されているようにprintf、出力はまだ実際のファイルに書き込まれていないため、の内部バッファからも出力を取得します。-の後にstdoutを追加することで、これを「修正」できます。fflush(stdout);printf

于 2013-02-01T14:41:39.263 に答える