กำลังพยายามสร้างกระบวนการลูก 2 กระบวนการและหลาน 1 คนที่ทำงานตามลำดับ

ดังนั้นฉันจึงพยายามสร้างกระบวนการลูก 2 กระบวนการและกระบวนการหลานหนึ่งกระบวนการจากลูกคนแรก ฉันกำลังพยายามเรียกใช้กระบวนการลูกคนแรก จากนั้นหลาน จากนั้นจึงลูกคนที่สองโดยที่ผู้ปกครองเรียก pid เมื่อกระบวนการเสร็จสิ้น ฉันติดอยู่อย่างสมบูรณ์ - ฉันมีโค้ดหลายเวอร์ชัน แต่ไม่สามารถทำให้มันเริ่มทำงานตามลำดับที่ถูกต้องได้ ความช่วยเหลือคำแนะนำหรือลิงก์ใด ๆ จะได้รับการชื่นชมอย่างมาก

ผลลัพธ์ที่ต้องการจะเป็น

- ฉันเป็นลูกคนแรก

----ฉันเป็นหลาน

ฉันเป็นผู้ปกครอง ลูกคนแรกมี pid 21505

- ฉันเป็นลูกคนแรก หลานมี p21506

-ลองอีกครั้ง

-- ฉันเป็นลูกคนที่สอง

-- -->ลูกคนที่สอง: ถ่ายโอน 1317 ไบต์

ฉันเป็นผู้ปกครองอีกครั้ง ลูกคนที่สองมี pid 21507

ผู้ปกครอง-เด็ก 21507 เรียบร้อยแล้ว

-ลองอีกครั้ง

**** ควรดูไฟล์ lab4.c 20 บรรทัดแรกที่นี่

ผู้ปกครอง - ลูกอื่น 21505 เสร็จแล้ว

int main(int* argc, char* args[])
{
pid_t child1, child2, gchild; //process ids
child1 = fork();           //Create the two child processes
if (child1 == 0)
{ // parent
    child2 = fork();
    if (child2 == 0)
    { //parent
        printf("P: first child has pid %d\n", child1);
        printf("P: second child has pid %d\n", child2);

        pid_t wpid; // process id that is finished
        int status; //status code returned by process  
                    //Wait for all child processes to complete
        while ((wpid = wait(&status)) > 0)
        {
            if (wpid > 0)
            {
                printf("P: Child %d is done \n", wpid);
            }
        };

        exit(0); //exit main parent process
    }
    else
    {
        //Second process's code

        printf("SC: I am the second child.\n");
        int totalBytes = 0; //total number of bytes in the file we are going to read in
        char buffer[2056]; //file contents size 2056 bytes
        ssize_t read_bytes = 0; //Bytes from each chunk get placed here temporarily

        ///Read in file contents: home/common/lab_sourcefile
        int fd_in = open("/home/COIS/3380/lab4_sourcefile", O_RDONLY);//open the file
        do
        {
            //read the file chunk by chunk to the buffer
            read_bytes = read(fd_in, buffer, (size_t)2056);

            // End of file or error.
            if (read_bytes <= 0)
            {
                break; //done reading file
            }

            //Save the total number of bytes
            totalBytes = totalBytes + read_bytes;
        } while (1); //infinite loop until we are done reading the file

        //Write out contents to: lab4_file_copy
        char filepath[1024]; //temp path
        getcwd(filepath, sizeof(filepath)); //Get the current working directory
        strcat(filepath, "/lab4_file_copy"); //Tack on the filename
        int fd = open(filepath, O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH); //open the file. O_RDWR = read and write flag, O_CREAT = create if doesnt exist, S_* flags are permission flags from fstat 
        write(fd, buffer, strlen(buffer)); //write to the file

        close(fd_in);//close file we were reading
        close(fd); //close copy file

        // print out the number of bytes the file
        printf("SC: --> Second child: %d bytes transferred.\n", totalBytes);

        exit(0); //done kill second child process
    }
}
else
{
    //First child process

    printf("FC: I'm the first child.\n");

    //Create the granchild process
    gchild = fork();
    if (gchild == 0)
    {
        printf("GC: I am the grandchild.\n");

        sleep(3); //sleep for 3 seconds

        printf("GC: #### Output start ####\n");
        execlp("head", "head", "-n", "20", "l.c", NULL); //this should exit automatically
        printf("ERROR: execlp command failed\n");//This will only run if the execlp process fails
        exit(1); //FAILED!
    }
    else
    {
        //Output the granchild pid
        printf("FC: I am the first child, grandchild has pid %d\n", gchild);
        int grandchildStatus;
        //Wait for grandchild process to be done. Polling...
        while ((waitpid(gchild, &grandchildStatus, WNOHANG)) != gchild)
        {
            printf("FC: Try again\n");
            sleep(1);
        };
        printf("GC: #### Output end ####\n");
        //End of first child. Grandchild must have completed.

        exit(0); //Done. kill first child process
    }
}

}


person sidelaunch    schedule 09.11.2017    source แหล่งที่มา
comment
หากคุณสลับบรรทัดที่ 3 และบรรทัดที่สี่ คุณสามารถซิงค์กับการโทร wait หลังจากแต่ละทางแยกได้ หากคุณต้องการเหมือนเดิม คุณจะต้องมีกลไกการซิงค์เพิ่มเติม มีตัวเลือกมากมาย: ไปป์ สัญญาณ เซมาฟอร์หน่วยความจำที่ใช้ร่วมกัน ฯลฯ เลือกเลย   -  person PSkocik    schedule 09.11.2017
comment
เรียนรู้เซมาฟอร์   -  person Christian Gibbons    schedule 09.11.2017


คำตอบ (1)


โดยทั่วไปมีข้อบกพร่องสองประการในโปรแกรมของคุณ:

  • else ส่วนสุดท้าย:

    คุณเรียก fork ดังนั้นทุกสิ่งที่อยู่หลังฟังก์ชัน fork จะถูกดำเนินการในทั้งสองกระบวนการ

    ทั้งผู้ปกครองและลูกคนที่สองจะพิมพ์: "ฉันเป็นผู้ปกครอง ลูกคนแรกมี pid..."

    เพื่อแก้ไขปัญหานี้ คุณจะต้องเพิ่ม if(child2 == 0) (ภายในบล็อก else)...

  • ลำดับของคำแนะนำ:

    เมื่อคุณเริ่มกระบวนการลูก กระบวนการลูกจะ จริงๆ ทำงานในเวลาเดียวกันกับกระบวนการหลัก:

    หากกระบวนการหนึ่งพิมพ์ว่า "Hello world." และอีกกระบวนการพิมพ์ว่า "นี่คือการทดสอบ" คุณอาจเห็นข้อความต่อไปนี้บนหน้าจอ: "นี่ สวัสดี คือ โลก การทดสอบ" (หรือคล้ายกัน) เพราะทั้งสองกระบวนการเป็น เขียนลงหน้าจอไปพร้อมๆ กัน

    คุณสามารถใช้ฟังก์ชัน waitpid ในพาเรนต์ของกระบวนการลูกเพื่อรอจนกว่ากระบวนการลูกจะเสร็จสิ้นเพื่อให้แน่ใจว่ากระบวนการลูกเสร็จสิ้นก่อนที่พาเรนต์จะดำเนินการต่อ (พิมพ์ข้อความ)

    อย่างไรก็ตาม หากคุณต้องการพิมพ์ข้อความในกระบวนการหลักก่อน คุณจะต้องหาวิธีหยุดการพิมพ์ข้อความย่อยและรอให้กระบวนการหลักพิมพ์เสร็จ

    ตัวอย่างเช่น คุณอาจใช้ raise(SIGSTOP); เพื่อหยุดกระบวนการที่กำลังทำงานอยู่ ในกระบวนการอื่น ให้ใช้ kill(pid, SIGCONT); เพื่อดำเนินการต่อในขั้นตอนอื่น pid ซึ่งกำลังรออยู่:

    child = fork();
    if(child == 0)
    {
        raise(SIGSTOP); /* Wait for the parent */
        /* Do something */
    }
    else
    {
        /* Do something */
        kill(child, SIGCONT); /* Tell the child to continue */
    }
    

... อย่างไรก็ตาม: ดังที่ PSkocik กล่าวไว้แม้ในกรณีนี้โปรแกรมของคุณอาจหยุดทำงาน - ดังนั้นมันจึงไม่ง่ายอย่างนั้น!

person Martin Rosenau    schedule 09.11.2017
comment
จะเกิดอะไรขึ้นถ้า SIGCONT ถูกส่งก่อน SIGSTOP? - person PSkocik; 09.11.2017