Различия между ветвлением и должностным лицом

В то время как я соглашаюсь с ответом Thomas (+1;)), я хотел бы добавить протест, что я приму столбец, который Вы не делаете , хотят, содержит едва любые данные. Если это содержит огромные суммы текста, xml или двоичных блобов, то не торопитесь для выбора каждого столбца индивидуально. Ваша производительность пострадает иначе. За Ваше здоровье!

194
задан krpra 2 October 2017 в 20:19
поделиться

5 ответов

The use of fork and exec exemplifies the spirit of UNIX in that it provides a very simple way to start new processes.

The fork call basically makes a duplicate of the current process, identical in almost every way. Not everything is copied over (for example, resource limits in some implementations) but the idea is to create as close a copy as possible.

The new process (child) gets a different process ID (PID) and has the PID of the old process (parent) as its parent PID (PPID). Because the two processes are now running exactly the same code, they can tell which is which by the return code of fork - the child gets 0, the parent gets the PID of the child. This is all, of course, assuming the fork call works - if not, no child is created and the parent gets an error code.

The exec call is a way to basically replace the entire current process with a new program. It loads the program into the current process space and runs it from the entry point.

So, fork and exec are often used in sequence to get a new program running as a child of a current process. Shells typically do this whenever you try to run a program like find - the shell forks, then the child loads the find program into memory, setting up all command line arguments, standard I/O and so forth.

But they're not required to be used together. It's perfectly acceptable for a program to fork itself without execing if, for example, the program contains both parent and child code (you need to be careful what you do, each implementation may have restrictions). This was used quite a lot (and still is) for daemons which simply listen on a TCP port and fork a copy of themselves to process a specific request while the parent goes back to listening.

Similarly, programs that know they're finished and just want to run another program don't need to fork, exec and then wait for the child. They can just load the child directly into their process space.

Some UNIX implementations have an optimized fork which uses what they call copy-on-write. This is a trick to delay the copying of the process space in fork until the program attempts to change something in that space. This is useful for those programs using only fork and not exec in that they don't have to copy an entire process space.

If the exec is called following fork (and this is what happens mostly), that causes a write to the process space and it is then copied for the child process.

Note that there is a whole family of exec calls (execl, execle, execve and so on) but exec in context here means any of them.

The following diagram illustrates the typical fork/exec operation where the bash shell is used to list a directory with the ls command:

+--------+
| pid=7  |
| ppid=4 |
| bash   |
+--------+
    |
    | calls fork
    V
+--------+             +--------+
| pid=7  |    forks    | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash   |             | bash   |
+--------+             +--------+
    |                      |
    | waits for pid 22     | calls exec to run ls
    |                      V
    |                  +--------+
    |                  | pid=22 |
    |                  | ppid=7 |
    |                  | ls     |
    V                  +--------+
+--------+                 |
| pid=7  |                 | exits
| ppid=4 | <---------------+
| bash   |
+--------+
    |
    | continues
    V
353
ответ дан 23 November 2019 в 05:23
поделиться

fork() splits the current process into two processes. Or in other words, your nice linear easy to think of program suddenly becomes two separate programs running one piece of code:

 int pid = fork();

 if (pid == 0)
 {
     printf("I'm the child");
 }
 else
 {
     printf("I'm the parent, my child is %i", pid);
     // here we can kill the child, but that's not very parently of us
 }

This can kind of blow your mind. Now you have one piece of code with pretty much identical state being executed by two processes. The child process inherits all the code and memory of the process that just created it, including starting from where the fork() call just left off. The only difference is the fork() return code to tell you if you are the parent or the child. If you are the parent, the return value is the id of the child.

exec is a bit easier to grasp, you just tell exec to execute a process using the target executable and you don't have two processes running the same code or inheriting the same state. Like @Steve Hawkins says, exec can be used after you forkto execute in the current process the target executable.

52
ответ дан 23 November 2019 в 05:23
поделиться

fork () создает копию текущего процесса с выполнением в новом дочернем процессе, начиная сразу после вызова fork (). После fork () они идентичны, за исключением возвращаемого значения функции fork (). (Подробности см. В RTFM.) Затем два процесса могут еще больше расходиться, и один из них не может вмешиваться в работу другого, за исключением, возможно, каких-либо общих файловых дескрипторов.

exec () заменяет текущий процесс новым. Это не имеет ничего общего с fork (), за исключением того, что exec () часто следует за fork (), когда требуется запустить другой дочерний процесс, а не заменить текущий.

4
ответ дан 23 November 2019 в 05:23
поделиться

Они используются вместе для создания нового дочернего процесса. Сначала вызов fork создает копию текущего процесса (дочернего процесса). Затем из дочернего процесса вызывается exec , чтобы «заменить» копию родительского процесса новым процессом.

Процесс выглядит примерно так:

child = fork();  //Fork returns a PID for the parent process, or 0 for the child, or -1 for Fail

if (child < 0) {
    std::cout << "Failed to fork GUI process...Exiting" << std::endl;
    exit (-1);
} else if (child == 0) {       // This is the Child Process
    // Call one of the "exec" functions to create the child process
    execvp (argv[0], const_cast<char**>(argv));
} else {                       // This is the Parent Process
    //Continue executing parent process
}
7
ответ дан 23 November 2019 в 05:23
поделиться

Я думаю, что некоторые концепции из «Расширенное программирование Unix» Марка Рочкинда помогли понять различные роли fork () / exec () , особенно для тех, кто привык к модели Windows CreateProcess () :

Программа представляет собой набор инструкций и данных, которые хранятся в обычном файле на диске. (из 1.1.2 Программы, процессы и потоки)

.

Чтобы запустить программу, ядру сначала предлагается создать новый процесс , который представляет собой среду, в которой выполняется программа. (также из 1.1.2 Программы, процессы и потоки)

.

Невозможно понять системные вызовы exec или fork без полного понимания различия между процессом и программой. Если эти условия новы для вас, вы можете вернуться и просмотреть Раздел 1.1.2. Если вы готовы продолжить, мы резюмируем различие в одном предложении: процесс - это среда выполнения, которая состоит из сегментов инструкций, пользовательских данных и системных данных, а также множества других ресурсов, полученных во время выполнения. , тогда как программа - это файл, содержащий инструкции и данные, которые используются для инициализации сегментов инструкций и пользовательских данных процесса. (с 5.3 exec Системные вызовы)

Как только вы поймете разницу между программой и процессом, поведение функции fork () и exec () может можно резюмировать следующим образом:

  • fork () создает дубликат текущего процесса
  • exec () заменяет программу в текущем процессе другой программой

(это, по сути, упрощенное 'для гораздо более подробный ответ paxdiablo для чайников )

31
ответ дан 23 November 2019 в 05:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: