cabang fork () lebih dari yang diharapkan?

186

Pertimbangkan potongan kode berikut:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    int i;
    for(i = 0; i < 2; i++)
    {
        fork();
        printf(".");
    }
    return 0;
}

Program ini menghasilkan 8 titik. Bagaimana itu bisa terjadi? Bukankah seharusnya ada 6 titik saja?

Nikolay Kovalenko
sumber
14
ideone.com/B9HXL
Antonio Pérez

Jawaban:

245

Yang fork()primitif sering merentangkan imajinasi. Sampai Anda merasakannya, Anda harus melacak di atas kertas apa setiap operasi itu dan menghitung jumlah proses. Jangan lupa bahwa fork () membuat salinan hampir sempurna dari proses saat ini. Perbedaan paling signifikan (untuk sebagian besar tujuan) adalah bahwa fork()nilai pengembalian berbeda antara orang tua dan anak. (Karena kode ini mengabaikan nilai pengembalian, tidak ada bedanya.)

Jadi, pada awalnya, ada satu proses. Itu menciptakan proses kedua, yang keduanya mencetak titik dan loop. Pada iterasi kedua mereka, masing-masing membuat salinan lain, jadi ada empat proses mencetak satu titik, dan kemudian keluar. Jadi kami dapat dengan mudah menghitung enam titik, seperti yang Anda harapkan.

Namun, yang printf()sebenarnya dilakukan adalah buffer outputnya. Jadi titik pertama dari ketika hanya ada dua proses tidak muncul saat ditulis. Titik-titik itu tetap berada di buffer — yang diduplikasi di fork (). Tidak sampai proses keluar akan muncul titik buffered. Empat proses mencetak titik buffered, ditambah yang baru memberikan 8 titik.

Jika Anda ingin menghindari perilaku itu, teleponlah fflush(stdout);setelahnya printf().

wallyk
sumber
12
Terima kasih, saya tidak tahu bahwa buffer duplikat dengan fork (). Ini menjelaskan perilaku yang aneh.
Nikolay Kovalenko
1
Bukankah seharusnya memberi 10 titik, bukan 8? Karena 4 generasi kedua anak-anak mewarisi titik buffered, tambahkan dot mereka sendiri, lalu flush on exit, mereka akan mencetak total 8 dot, tetapi kemudian 2 proses generasi pertama masih memiliki satu dot yang masing-masing buffer, dan flush yang keluar, memberikan total 10.
psusi
12
@psusi Salah satu proses generasi kedua adalah proses generasi pertama. fork()tidak membuat 2 lalu keluar, itu hanya menciptakan 1 proses lagi.
Izkata
70

Anda memiliki buffer yang tidak berkomitmen dalam aliran output . stdout adalah buffer-line, dan buffer direplikasi bersama dengan sisa proses. Ketika program berakhir, buffer yang tidak terikat ditulis dua kali (satu kali untuk setiap proses). Keduanya menggunakan

printf("a\n");

dan

printf("a "); fflush(stdout);

jangan menunjukkan masalahnya.

Dalam contoh pertama Anda, Anda membuat empat proses yang memiliki masing-masing dua titik di buffer aliran output. Ketika setiap aliran berakhir, ia mengguyur buffer-nya, menghasilkan delapan titik.

thiton
sumber
2

ketika saya = 0

Process_1: Teks yang disangga = 1 titik

Process_2 (dibuat oleh Process_1): Teks yang disangga = 1 titik

ketika saya = 1

Process_3 (dibuat oleh Process_1): Mewarisi 1 titik buffer dari Process_1 dan mencetak 1 titik dengan sendirinya. Total Process_3 mencetak 2 titik.

Process_4 (dibuat oleh Process_2): Mewarisi 1 buffered dot dari Process_2 dan mencetak 1 dot dengan sendirinya. Total Process_4 mencetak 2 titik.

Process_1: Mencetak 2 titik (Satu titik buffered ketika i = 0 dan titik lainnya ketika i = 1)

Process_2: Mencetak 2 titik (Satu titik buffered ketika i = 0 dan titik lainnya ketika saya = 1)

Hasil Akhir: 8 titik. :)

Tauseef
sumber