2009-11-03 30 views
15

Vì vậy, tôi có chức năng này dành cho N số quy trình con. Tuy nhiên nó dường như được forking hơn quy định. Bạn có thể cho tôi biết tôi đang làm gì sai không? Cảm ơnVấn đề forking fork() nhiều quá trình Unix

void forkChildren(int nChildren){ 
    int i; 
    for(i = 1; i <= nChildren; i++){ 
     pid = fork(); 
     if(pid == 0)   
      printf("I'm a child: %d PID: %d\n",i, getpid()); 
    } 

} 

Trong Tôi gọi chính:

forkChildren(5); 

Tôi đang mong đợi kết quả như sau:

I'm a child: 1 PID: 2990 
I'm a child: 2 PID: 2991 
I'm a child: 3 PID: 2992 
I'm a child: 4 PID: 2993 
I'm a child: 5 PID: 2994 

Nhưng thay vào đó tôi nhận được như sau:

I'm a child: 1 PID: 2990 
I'm a child: 2 PID: 2991 
I'm a child: 3 PID: 2992 
I'm a child: 4 PID: 2993 
I'm a child: 5 PID: 2994 
[email protected]:~/directory/$ I'm a child: 2 PID: 2999 
I'm a child: 3 PID: 3000 
I'm a child: 3 PID: 3001 
I'm a child: 4 PID: 3002 
I'm a child: 5 PID: 3003 
I'm a child: 5 PID: 3004 
I'm a child: 4 PID: 3005 
I'm a child: 5 PID: 3006 
I'm a child: 4 PID: 3007 
I'm a child: 5 PID: 3008 
I'm a child: 3 PID: 3011 
I'm a child: 4 PID: 3012 
I'm a child: 4 PID: 3010 
I'm a child: 5 PID: 3013 
I'm a child: 5 PID: 3014 
I'm a child: 5 PID: 3015 
I'm a child: 4 PID: 3018 
I'm a child: 5 PID: 3019 
I'm a child: 5 PID: 3020 
I'm a child: 5 PID: 3021 
I'm a child: 5 PID: 3023 
I'm a child: 5 PID: 3025 
I'm a child: 5 PID: 3024 
I'm a child: 4 PID: 3022 
I'm a child: 5 PID: 3026 
I'm a child: 5 PID: 3027 
+2

Tôi thấy bây giờ. Tôi chỉ cần đặt lối ra (0); sau mỗi đứa trẻ in thông tin của nó. – user69514

Trả lời

14

Cuộc gọi fork() sinh ra một quy trình mới bắt đầu thực hiện tại cùng một điểm chính xác nơi ngã ba xảy ra. Vì vậy, có vẻ như ngã ba "trả về hai lần"

Điều đang xảy ra ở đây là lệnh fork() của bạn trả về hai lần, vì vậy cả quá trình cha và con sẽ tiếp tục lặp lại và sinh ra các quy trình mới. Mỗi đứa trẻ (của cả cha/mẹ và con ban đầu) sau đó lại núp, lặp lại gấp đôi số lượng quy trình ...

+0

Không tăng gấp đôi. Những đứa trẻ vẫn đang tăng thêm i trong vòng lặp để mỗi thế hệ thứ hai sẽ chỉ tạo ra bốn đứa cháu, * không * 5. Đó là một dạng của giai thừa. Nhưng, khác với * nhỏ * nitpick, câu trả lời tốt. – paxdiablo

+0

@paxdiablo: Đứa trẻ tăng i, nhưng chỉ bản sao cục bộ của nó. Nó không ảnh hưởng đến bản sao của tôi. –

1

Mỗi trẻ em pr ocess chọn lên và tiếp tục vòng lặp.

Nói cách khác, con 1 được sinh ra và tiếp tục với lặp # 2 của vòng lặp, vv

Khi một quá trình được chia hai, một bản sao của quá trình hiện tại được đưa ra: kết quả quá trình con tiếp tục thực hiện sau khi ngã ba() gọi điện. Đó là lý do tại sao bạn phải chăm sóc mã trả về trong logic của bạn.

15

Khi bạn fork một quá trình, về cơ bản bạn sẽ có hai bản sao chính xác của quy trình và cả hai trong số họ sẽ tiếp tục chạy.

Vì vậy, những gì đang xảy ra là trẻ em đang tiếp tục vòng lặp trong không gian quá trình của riêng mình (sau khi in đầu ra của chúng) cũng như làm cha mẹ thực hiện. Và, trên thực tế, bởi vì những đứa trẻ này cũng đang bị nghẹt thở, các cháu cũng sẽ tiếp tục từ thời điểm đó. Tôi chắc chắn rằng có một công thức để thực sự tìm ra bao nhiêu trẻ em bạn kết thúc với (có thể là một cái gì đó như N!) Nhưng tôi không có năng lượng để tìm ra nó vào lúc này. Tốt hơn để sử dụng giải pháp sau.

Cách để biết sự khác biệt giữa cha mẹ và con là giá trị trả lại từ fork.

  • Nếu bạn lấy lại -1, bạn là phụ huynh và fork không thành công.
  • Nếu bạn lấy lại số không, bạn là con.
  • Nếu bạn lấy lại số dương, bạn là phụ huynh và con số đó là con PID (để bạn có thể điều khiển nó hoặc wait cho nó).

Dưới đây là một số mã kiểm tra:

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

void forkChildren (int nChildren) { 
    int i; 
    pid_t pid; 
    for (i = 1; i <= nChildren; i++) { 
     pid = fork(); 
     if (pid == -1) { 
      /* error handling here, if needed */ 
      return; 
     } 
     if (pid == 0) { 
      printf("I am a child: %d PID: %d\n",i, getpid()); 
      sleep (5); 
      return; 
     } 
    } 
} 

int main (int argc, char *argv[]) { 
    if (argc < 2) { 
     forkChildren (2); 
    } else { 
     forkChildren (atoi (argv[1])); 
    } 
    return 0; 
} 

và một số đầu ra để cho bạn thấy những gì đang xảy ra:

pax> forktest 5 
I am a child: 1 PID: 4188 
I am a child: 2 PID: 4180 
I am a child: 3 PID: 5396 
I am a child: 4 PID: 4316 
I am a child: 5 PID: 4260 

pax> _ 
+0

Thay đổi để làm rõ. – paxdiablo

+0

Tôi đang giúp một người bạn có nhiệm vụ OS và chức năng trên hoạt động tốt, thanx! –

1

Trong bài tập này, tôi muốn sử dụng đệ quy chứ không phải là một vòng lặp for. Bằng cách này bạn có thể có lệnh fork() được gọi nhiều lần nhưng chỉ trên một trong hai bản sao của quá trình. Bạn có thể làm cho quá trình con đẻ trứng một tiến trình con khác, do đó có ông bà, ông bà, v.v. hoặc bạn có thể gọi ngã ba() ở bên mẹ, có một "cha" và nhiều con. Đây là mẫu mã thực hiện giải pháp sau:

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

int nChildren; 

void myFork(int n); 

int main(int argc, char *argv[]) { 

    // just a check on the number of arguments supplied 
    if (argc < 2) { 
    printf("Usage: forktest <number_of_children>\n"); 
    printf("Example: forktest 5 - spawns 5 children processes\n"); 
    return -1; 
    } 

    nChildren = atoi(argv[1]); 
    // starting the recursion... 
    myFork(nChildren-1); 
    return 0; 
} 

// the recursive function 
void myFork(int n) { 
    pid_t pid; 

    pid = fork(); 

    // the child does nothing but printing a message on screen 
    if (pid == 0) { 
    printf("I am a child: %d PID: %d\n", nChildren-n, getpid()); 
    return; 
    } 

    // if pid != 0, we're in the parent 
    // let's print a message showing that the parent pid is always the same... 
    printf("It's always me (PID %d) spawning a new child (PID %d)\n", getpid(), pid); 
    // ...and wait for the child to terminate. 
    wait(pid); 

    // let's call ourself again, decreasing the counter, until it reaches 0. 
    if (n > 0) { 
    myFork(n-1); 
    } 
} 
Các vấn đề liên quan