2012-06-21 8 views
182

Hãy xem xét đoạn mã sau:ngã ba() nhiều hơn dự kiế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; 
} 

Chương trình này xuất ra 8 dấu chấm. Không thể nào? Không nên có 6 dấu chấm thay thế?

+0

[Kiểm tra bài đăng này] (http://stackoverflow.com/questions/10909011/how-to-use-fork-to-create-only-2-child-processes/10909090#10909090) – tuxuday

+14

http: //ideone.com/B9HXL –

Trả lời

241

Nguyên mẫu fork() thường kéo dài trí tưởng tượng. Cho đến khi bạn có được một cảm giác cho nó, bạn nên theo dõi trên giấy những gì từng hoạt động và tài khoản cho số lượng các quy trình. Đừng quên rằng fork() tạo ra một bản sao gần như hoàn hảo của quá trình hiện tại. Sự khác biệt đáng kể nhất (đối với hầu hết các mục đích) là giá trị trả về của fork() khác nhau giữa cha mẹ và con. (Vì mã này bỏ qua giá trị trả về, nó không tạo ra sự khác biệt.)

Vì vậy, lúc đầu, có một quy trình. Điều đó tạo ra một quá trình thứ hai, cả hai đều in một dấu chấm và vòng lặp. Trong lần lặp thứ hai của họ, mỗi lần tạo một bản sao khác, vì vậy có bốn quy trình in một dấu chấm và sau đó thoát ra. Vì vậy, chúng tôi có thể dễ dàng tính đến sáu dấu chấm, như bạn mong đợi.

Tuy nhiên, những gì printf() thực sự là bộ đệm đầu ra của nó. Vì vậy, dấu chấm đầu tiên khi chỉ có hai quy trình không xuất hiện khi được viết. Các chấm đó vẫn nằm trong vùng đệm — được sao chép ở ngã ba(). Nó không phải là cho đến khi quá trình sắp thoát ra mà dấu chấm đệm xuất hiện. Bốn quy trình in một chấm đệm, cộng với một quy trình mới cho 8 dấu chấm.

Nếu bạn muốn tránh hành vi đó, hãy gọi fflush(stdout); sau printf().

+12

Cảm ơn, tôi không biết rằng các bản sao đệm với fork(). Nó giải thích một hành vi kỳ lạ như vậy. –

+1

Không nên cho 10 chấm, không phải 8? Kể từ khi trẻ em thế hệ thứ 4 thừa kế dấu chấm đệm, thêm dấu chấm của riêng chúng, sau đó tuôn ra khi thoát, chúng sẽ in tổng cộng 8 dấu chấm, nhưng sau đó 2 quy trình thế hệ đầu tiên sẽ vẫn có một chấm mỗi bộ đệm và xóa các dấu chấm đó khi thoát, tổng cộng là 10. – psusi

+12

@psusi Một trong những quy trình thế hệ thứ hai _is_ một quá trình thế hệ thứ nhất. 'fork()' không tạo ra 2 rồi thoát ra, nó chỉ tạo thêm 1 tiến trình nữa. – Izkata

70

Bạn có bộ đệm không được cam kết trong luồng đầu ra. stdout là dòng đệm, và bộ đệm được nhân rộng cùng với phần còn lại của quá trình. Khi chương trình kết thúc, bộ đệm không cam kết được viết hai lần (một lần cho mỗi quá trình). Cả hai sử dụng

printf("a\n"); 

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

không thể hiện vấn đề.

Trong ví dụ đầu tiên của bạn, bạn tạo bốn quy trình có hai dấu chấm trong bộ đệm luồng đầu ra của chúng. Khi mỗi dòng kết thúc, nó xóa bộ đệm của nó, tạo ra tám dấu chấm.

2

khi i = 0

Process_1: văn bản đệm = 1 dấu chấm

Process_2 (tạo ra bởi Process_1): Đệm text = 1 dấu chấm

khi i = 1

Process_3 (được tạo bởi Process_1): Thừa kế 1 chấm đệm từ Process_1 và tự in 1 dấu chấm. Trong tổng số Process_3 in 2 dấu chấm.

Process_4 (được tạo bởi Process_2): Thừa kế 1 chấm đệm từ Process_2 và tự in 1 dấu chấm. Trong tổng số Process_4 in 2 dấu chấm.

Process_1: In 2 chấm (Một dấu chấm đệm khi i = 0 và chấm khác khi i = 1)

Process_2: In 2 chấm (Một đệm dot khi i = 0 và chấm khác khi i = 1)

Kết quả cuối cùng: 8 dấu chấm. :)