fork () şubeleri beklenenden fazla mı?


186

Aşağıdaki kod parçasını düşünün:

#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;
}

Bu program 8 nokta verir. Bu nasıl mümkün olabilir? Bunun yerine 6 nokta olmamalı mı?



Yanıtlar:


245

fork()İlkel genellikle hayal gücünü zorlayacak. Bir fikir edinene kadar, her işlemin ne olduğunu kağıt üzerinde izlemeli ve süreç sayısını hesaba katmalısınız. Fork () öğesinin geçerli sürecin mükemmel bir kopyasını oluşturduğunu unutmayın. En önemli fark (çoğu amaç için) fork()dönüş değerinin ebeveyn ve çocuk arasında farklılık göstermesidir. (Bu kod dönüş değerini yok saydığından fark etmez.)

İlk başta bir süreç var. Bu, her ikisi de nokta ve döngü basan ikinci bir işlem oluşturur. İkinci yinelemelerinde, her biri başka bir kopya oluşturur, bu nedenle bir nokta yazdırıp çıkacak dört işlem vardır. Böylece, beklediğiniz gibi altı noktayı kolayca hesaplayabiliriz.

Ancak, printf()gerçekten yaptığı şey çıktısını tamponlamaktır. Bu nedenle, sadece iki işlemin yapıldığı ilk nokta yazıldığında görünmez. Bu noktalar tamponda kalır (çatalda () çoğaltılır). İşlem, arabelleğe alınan noktanın görünmesi bitene kadar değildir. Tamponlanmış bir nokta basarken dört işlem, artı yeni nokta 8 nokta verir.

O davranıştan kaçınmak istiyorsa, çağrı fflush(stdout);sonra printf().


12
Teşekkürler, arabellek çatal () ile çoğaldığını bilmiyordum. Böyle garip bir davranışı açıklıyor.
Nikolay Kovalenko

1
Bu 8 değil 10 nokta vermemeli mi? 4 ikinci nesil çocuk tamponlu noktayı miras aldıklarından, kendileri ekledikten sonra çıkışta yıkadıklarından, toplam 8 nokta basacaklardı, ancak daha sonra 2 nesil neslin her biri tamponlanmış bir noktaya sahip olacak ve çıkışta olanları yıkayacak, toplam 10 veriyor.
psusi

12
@psusi İkinci nesil süreçlerden biri birinci nesil bir süreçtir. fork()2 oluşturmaz, sonra çıkar, yalnızca 1 işlem daha oluşturur.
Izkata

70

Çıkış akışlarında taahhüt edilmemiş arabellekleriniz var . stdout satır tamponludur ve tampon işlemin geri kalanıyla birlikte çoğaltılır. Program sona erdiğinde, taahhüt edilmeyen arabellek iki kez yazılır (her işlem için bir kez). Her ikisi de

printf("a\n");

ve

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

sorunu sergilemeyin.

İlk örneğinizde, her iki noktanın çıktı akışı arabelleğinde bulunan dört işlem oluşturursunuz. Her akış sona erdiğinde, tamponunu temizler ve sekiz nokta oluşturur.


2

i = 0 olduğunda

Process_1: Arabelleklenmiş metin = 1 nokta

Process_2 (Process_1 tarafından oluşturuldu): Arabelleklenmiş metin = 1 nokta

i = 1 olduğunda

Process_3 (Process_1 tarafından oluşturuldu): Process_1 öğesinden 1 arabelleğe alınmış noktayı devralır ve 1 noktayı tek başına yazdırır. Toplam Process_3 2 nokta yazdırır.

Process_4 (Process_2 tarafından oluşturuldu): Process_2'den 1 arabelleğe alınmış nokta devralır ve 1 noktayı tek başına yazdırır. Toplam Process_4 2 nokta yazdırır.

Process_1: 2 nokta yazdırır (i = 0 olduğunda bir tamponlanmış nokta ve i = 1 olduğunda başka bir nokta)

Process_2: 2 nokta yazdırır (i = 0 olduğunda bir tamponlanmış nokta ve i = 1 olduğunda başka bir nokta)

Son Çıktı: 8 nokta. :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.