GNU/Linux >> Belajar Linux >  >> Linux

Fork panggilan sistem () dan fungsi execv

Anda perlu memahami bagaimana fork dan execv bekerja sama.

  • fork() membuat duplikat dari proses saat ini, mengembalikan 0 ke turunan, pid ke induk
  • fork() bisa gagal, dan mengembalikan -1 jika gagal, periksa itu
  • execv() mengganti proses induk duplikat dengan proses baru
  • pemasangan fork/exec biasa menggantikan proses anak dengan proses baru
  • sering kali Anda mem-fork lebih dari satu anak, dan ingin mereka berjalan secara bersamaan,
  • namun, Anda memintanya untuk berjalan secara berurutan, yaitu satu demi satu
  • jadi, Anda harus menunggu yang pertama selesai sebelum memulai yang kedua
  • sehingga Anda perlu menggunakan beberapa varian wait(), contoh di bawah ini menggunakan waitpid() untuk menunggu anak tertentu

Anda perlu stdlib untuk keluar (kalau-kalau execv gagal), dan errno, untuk mencetak alasannya,

//I'm trying to run two executables consecutively using this c code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

Anda mungkin ingin memeriksa alasan anak Anda keluar (core dump, signal, normal exit), jadi saya telah menambahkan fungsi ini,

#include <sys/types.h>
#include <sys/wait.h>

//WIFEXITED(status) returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
//WEXITSTATUS(status) returns the exit status of the child.  This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main().  This macro should only be employed if WIFEXITED returned true.
//WIFSIGNALED(status) returns true if the child process was terminated by a signal.
//WTERMSIG(status) returns the number of the signal that caused the child process to terminate.  This macro should only be employed if WIFSIGNALED returned true.
//WCOREDUMP(status) returns true if the child produced a core dump.  This macro should only be employed if WIFSIGNALED returned true.  This macro is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS).  Only use this enclosed in #ifdef WCOREDUMP ... #endif.
//WIFSTOPPED(status) returns true if the child process was stopped by delivery of a signal; this is only possible if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).
//WSTOPSIG(status) returns the number of the signal which caused the child to stop.  This macro should only be employed if WIFSTOPPED returned true.
//WIFCONTINUED(status) (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
int
exitreason(pid_t cid, int status)
{
    if( WIFEXITED(status) )
    {
        printf("child %d terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().\n",cid);
        if( WEXITSTATUS(status) )
        {
        printf("child %d exit status %d.  This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main().\n",cid,WEXITSTATUS(status));
        }
    }
    if( WIFSIGNALED(status) )
    {
        printf("child %d process was terminated by a signal.\n",cid);
        if( WTERMSIG(status) )
        {
        printf("child %d signal %d that caused the child process to terminate.\n",cid,WTERMSIG(status));
        }
        if( WCOREDUMP(status) )
        {
        printf("child %d produced a core dump.  WCOREDUMP() is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS).  Only use this enclosed in #ifdef WCOREDUMP ... #endif.\n",cid);
        }
    }
    if( WIFSTOPPED(status) )
    {
        printf("child %d process was stopped by delivery of a signal; this is only possible if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).\n",cid);
        if( WSTOPSIG(status) )
        {
        printf("child %d number of the signal which caused the child to stop.\n",cid);
        }
    }
    if( WIFCONTINUED(status) )
    {
        printf("child %d process was resumed by delivery of SIGCONT.\n");
    }
}

Dan inilah program Anda yang dianotasi dengan komentar yang menjelaskan bagian kode mana yang diproses oleh orang tua, dan mana oleh anak(ren).

int main (int argc, char *argv[])
{
    char proc1[] = "/bin/echo"; //"./prcs1";
    char proc2[] = "/bin/echo"; //"./prcs2";
    pid_t cid1, cid2, cidX;
    int status=0;
    int waitoptions = 0;
    //WNOHANG    return immediately if no child has exited.
    //WUNTRACED  also return if a child has stopped (but not traced via ptrace(2)).  Status for traced children which have stopped is provided even if this option is not specified.
    //WCONTINUED also return if a stopped child has been resumed by delivery of SIGCONT.
    int res;

    if( (cid1 = fork()) == 0 ) //child1
    {
        printf("in child1\n");
        if( (res = execv(proc1, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
        {
        printf("error: child1: %d exec failed %d\n", cid1, errno);
        printf("error: cannot execv %s\n",proc1);
        exit(91); //must exit child
        }
    }
    else if( cid1 > 0 ) //cid>0, parent, waitfor child
    {
        cidX = waitpid(cid1, &status, waitoptions);
        printf("child1: %d res %d\n", cid1, res);
        exitreason(cid1, status);
    }
    else //cid1 < 0, error
    {
        printf("error: child1 fork failed\n");
    }

    if( (cid2 = fork()) == 0 ) //child2
    {
        printf("in child2\n");
        if( (res = execv(proc2, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
        {
        printf("error: child2: %d exec failed %d\n", cid2, errno);
        printf("error: cannot execv %s\n",proc2);
        exit(92); //must exit child
        }
    }
    else if( cid2 > 0 ) //cid>0, parent, waitfor child
    {
        cidX = waitpid(cid2, &status, waitoptions);
        printf("child2: %d res %d\n", cid2, res);
        exitreason(cid2, status);
    }
    else //cid2 < 0, error
    {
        printf("error: child2 fork failed\n");
    }
}

Anda memiliki beberapa masalah. Pertama, jika Anda hanya ingin menjalankan dua program, Anda hanya perlu memanggil fork() satu kali. Kemudian jalankan satu program di proses induk dan satu lagi di proses anak. Kedua, Anda membuat argv array untuk diteruskan ke execv salah. Entri pertama harus berupa nama yang dapat dieksekusi. Lakukan sesuatu seperti:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char **argv)
{
    pid_t i = fork();
    if (i == 0)
    {
        execv("./prcs1", (char *[]){ "./prcs1", argv[1], NULL });
        _exit(1);
    }
    else if (i > 0)
    {
        execv("./prcs2", (char *[]){ "./prcs2", argv[0], NULL });
        _exit(2);
    }
    else
    {
        perror("fork failed");
        _exit(3);
    }
}

Perhatikan bahwa contoh ini tidak melakukan pemeriksaan kesalahan.


Anda belum banyak membaca tentang fork() saya rasa.

saat Anda memanggil fork() , itu membuat proses anak yang akan menjalankan kode yang sama dari fork.

fork() mengembalikan tiga jenis nilai

  • negatif yang menunjukkan kesalahan
  • positif yang mengatakan Anda berada dalam proses induk dan nilai menunjukkan ID proses anak
  • nol yang menyatakan bahwa Anda sedang dalam proses anak.

kode Anda akan terlihat seperti ini.

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

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

    int ret = fork();
    if(ret==0)
    {
       //child process
       execv("./prcs1", &argv[1]); // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
       printf("EXECV Failed from child\n");
    }
    else if(ret>0)
    {
       //parent process
       execv("./prcs2", argv);
       printf("EXECV Failed from parent\n");
    }
    else
    {
       //you will come here only if fork() fails.
       printf("forkFailed\n");
    }
    return 0;
}

Linux
  1. Proses Linux – ID Proses, fork, execv, wait, waitpid Fungsi C

  2. Kapan harus memeriksa EINTR dan mengulangi pemanggilan fungsi?

  3. system() batas panjang string fungsi

  1. Nilai pengembalian fungsi batas waktu

  2. Mengapa nomor panggilan sistem Linux di x86 dan x86_64 berbeda?

  3. fungsi panggilan dinyatakan di bawah ini

  1. Status Sistem dan Server

  2. Superblock, Inode, Dentry, dan File?

  3. Cara Membuat dan Memanggil Fungsi di Bash