Sau ngã ba (), đứa trẻ bắt đầu thực hiện ở đâu?


22

Tôi đang cố gắng học lập trình UNIX và bắt gặp một câu hỏi liên quan đến fork (). Tôi hiểu rằng fork () tạo ra một quy trình giống hệt của quy trình hiện đang chạy, nhưng nó bắt đầu từ đâu? Ví dụ: nếu tôi có mã

int main (int argc, char **argv)
{
    int retval;
    printf ("This is most definitely the parent process\n");
    fflush (stdout);
    retval = fork ();
    printf ("Which process printed this?\n");

    return (EXIT_SUCCESS);
}

Đầu ra là:

Đây chắc chắn là quy trình cha mẹ Quy trình
nào được in này?
Quy trình nào được in này?

Tôi nghĩ rằng điều đó fork()tạo ra một quy trình tương tự, vì vậy ban đầu tôi rằng trong chương trình đó, fork()cuộc gọi sẽ được gọi đệ quy mãi mãi. Tôi đoán rằng quá trình mới được tạo ra từ fork()bắt đầu sau fork()cuộc gọi?

Nếu tôi thêm mã sau đây, để phân biệt giữa quy trình cha và con,

if (child_pid = fork ()) printf ("This is the parent, child pid is %d\n", child_pid);
else printf ("This is the child, pid is %d\n",getpid ());

sau cuộc gọi fork (), tiến trình con bắt đầu thực hiện ở đâu?


5
man forkcó đủ chắc chắn để trả lời câu hỏi của bạn không, btw
alex

Câu trả lời:


23

Quá trình mới sẽ được tạo trong fork()cuộc gọi và sẽ bắt đầu bằng cách quay lại từ nó giống như cha mẹ. Giá trị trả về (mà bạn đã lưu trữ retval) từ fork()sẽ là:

  • 0 trong quá trình con
  • PID của trẻ trong quá trình cha mẹ
  • -1 trong cha mẹ nếu có một thất bại (tự nhiên không có con)

Mã kiểm tra của bạn hoạt động chính xác; nó lưu giá trị trả về từ fork()trong child_pidvà sử dụng ifđể kiểm tra xem nó có 0 hay không (mặc dù nó không kiểm tra lỗi)


13

Tôi nghĩ rằng fork () tạo ra một quy trình tương tự, vì vậy ban đầu tôi rằng trong chương trình đó, lệnh gọi fork () sẽ được gọi đệ quy mãi mãi. Tôi đoán rằng quá trình mới được tạo từ fork () bắt đầu sau lệnh gọi fork ()?

Vâng. Hãy đánh số dòng:

int main (int argc, char **argv)
{
    int retval;                                               /* 1 */
    printf ("This is most definitely the parent process\n");  /* 2 */
    fflush (stdout);                                          /* 3 */
    retval = fork ();                                         /* 4 */
    printf ("Which process printed this?\n");                 /* 5 */
    return (EXIT_SUCCESS);                                    /* 6 */
}

Luồng thực hiện là:

caller process     fork()  ...
                          
original program            exec()  2  3  4  5  6
                                               
forked program                                   5  6

... Điều này giải thích chính xác đầu ra bạn nhận được.

Nếu bạn muốn biết chương trình gốc và rẽ nhánh có thể hoạt động khác nhau như thế nào, vì chúng nhất thiết phải chia sẻ cùng một mã, hãy xem câu trả lời của Michael Mrozek.


Lưu ý rằng 1 không thực sự là một hướng dẫn. Cũng lưu ý rằng các chương trình gốc và các chương trình rẽ nhánh không thực sự chạy cùng một lúc - một trong hai chương trình sẽ phải chờ cho chương trình khác mang lại / được ưu tiên.
badp

1
Trên các hệ thống đa lõi / đa lõi, cả hai chương trình thực sự có thể chạy cùng một lúc.
jlliagre

@jilliagre Hệ thống đa lõi là về đa luồng thực sự. Đối với các hệ thống có nhiều CPU, tôi không biết đó có phải là trường hợp thực tế hay không . Tôi không phải là chuyên gia trong lĩnh vực này - và có vẻ như đó là một viễn cảnh không thể xảy ra. Nếu chúng ta đồng ý HĐH có thể chạy nhiều tiến trình cùng một lúc (thì nó sẽ xử lý đồng thời như thế nào?), Vào thời điểm chương trình gốc chạy lệnh 4 trên CPU, các CPU khác có thể đang bận chạy các tiến trình khác .
badp

Tôi có thể nói đó là một kịch bản rất có thể xảy ra, đặc biệt khi có một cuộc gọi hệ thống cơ bản với một số I / O xảy ra ở bước 5. Có tất cả các CPU bận rộn thực sự không phải là tình huống phổ biến vì CPU hiếm khi bị nghẽn cổ chai với các máy hiện tại. Có vẻ như bạn đang nhầm lẫn đa luồng và đa lõi.
jlliagre

8
Tôi có thể chỉ nhận xét để nói rằng những mũi tên chéo là tuyệt vời .
JBirch

0

Giải pháp thực sự cho vấn đề này là

switch (fork()) {
    case -1 :
        fprintf (stderr, "fork failed (%s)\n", strerror(errno));
        break;
    case 0 :  // child process comes here
        break;
    default : // parent process
        break;
}

// all continue here

-1

bất cứ mã nào ngay sau fork(), được sao chép vào tiến trình con và không trộn lẫn tiến trình cha và con, chúng là hai thực thể khác nhau, có cùng môi trường (trùng lặp, không chia sẻ).

Bây giờ hãy xem đầu ra của bạn ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.