forking() и CreateProcess()

Являются ли forking() и CreateProcess(со всеми необходимыми аргументами) одним и тем же для Linux и WinXP соответственно?

Если они разные, то может ли кто-нибудь объяснить разницу с точки зрения того, что происходит в каждом из двух случаев?

Спасибо


person Sunny    schedule 12.12.2012    source источник


Ответы (3)


Они делают разные вещи и в разных системах. CreateProcess — это функция только для Windows, а fork — только для систем POSIX (например, Linux и Mac OSX).

Системный вызов fork создает новый процесс и продолжает выполнение как в родительском, так и в дочернем процессах с точки, где была вызвана функция fork. CreateProcess создает новый процесс и загружает программу с диска. Единственное сходство заключается в том, что конечным результатом является создание нового процесса.

Для получения дополнительной информации прочитайте соответствующую страницу руководства по адресу CreateProcess и fork.

person Some programmer dude    schedule 12.12.2012

CreateProcess выполняет следующие шаги:

  • Создайте и инициализируйте блок управления процессом (PCB) в ядре.
  • Создайте и инициализируйте новое адресное пространство.
  • Загрузите программу prog в адресное пространство.
  • Скопируйте аргументы args в память в адресное пространство.
  • Инициализируйте аппаратный контекст, чтобы начать выполнение при «старте».
  • Сообщите планировщику, что новый процесс готов к запуску.

Форк Unix выполняет следующие шаги:

  • Создайте и инициализируйте блок управления процессом (PCB) в ядре
  • Создать новое адресное пространство
  • Инициализировать адресное пространство копией всего содержимого адресного пространства родителя.
  • Наследовать контекст выполнения родителя (например, любые открытые файлы)
  • Сообщите планировщику, что новый процесс готов к запуску

Он создает полную копию родительского процесса, и родительский процесс не настраивает среду выполнения для дочернего процесса, поскольку родительский процесс доверяет своей собственной настройке. Дочерний процесс является полной копией родителя, за исключением его идентификатора процесса (что возвращает ответвление). Разветвленный процесс продолжает выполнять ту же программу, что и его родитель, пока не выполнит явное выполнение команды exec. Когда дочерний процесс вызывает exec which, новый исполняемый образ помещается в память и запускается.

Насколько эффективно сделать полную копию? копирование при записи. Он действительно копирует только карту виртуальной памяти. Все сегменты в таблице сегментов доступны только для чтения. Если родительский или дочерний сегмент редактирует данные в сегменте, генерируется исключение, и ядро ​​создает его полную копию в памяти. Это хорошо объяснено в этом ответе.

Существует несколько преимуществ совместного использования ресурсов между родительским и дочерним элементами: - интуитивно понятное управление ресурсами: требуется меньше памяти для поддержания состояния процессов - ресурсы кэша являются общими, что означает большую временную локальность данных, когда данные не перезаписываются, что повышает производительность. потому что извлечение данных из больших кешей/дисков занимает много времени.

Недостатки общих ресурсов: - когда операции записи являются общими, это переводит данные в недопустимое состояние для другого процесса, и это приводит к промахам когерентности, что дорого обходится, если дочерний процесс выполняется на отдельном ядре, поскольку изменения должны распространяться до кэша L3.

В общем, программы читают чертовски больше, чем пишут, обычно дочернему/родительскому программам нужно только производить запись в свой стек, и это небольшая часть их программного блока.

Кроме того, вилка Unix отличается тем, что она возвращается дважды: один раз в родительском (идентификатор процесса его дочернего процесса), один раз в дочернем (0, поздравляю, вы новый дочерний процесс), и именно так мы различаем в нашем коде, если мы является ребенком или родителем.

Unix Exec делает следующее:

  • Загрузите программу prog в текущее адресное пространство.
  • Скопируйте аргументы args в память в адресное пространство.
  • Инициализируйте аппаратный контекст, чтобы начать выполнение с «старта».

у родителя есть возможность подождать, пока ребенок закончит. Когда дочерний процесс завершается, когда вызывается выход, уведомляется ожидание родителя.

person merhoo    schedule 12.12.2018

Я приведу два примера, чтобы показать разницу:
fork():

#include "stdio.h"  
#include "stdlib.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int fac(int);
int main(void)  
{
    int child_ret,input_num=-1;
    pid_t pid1;
    while(input_num<0){
        printf("\nPlease input a non-negative number:  ");
        scanf("%d",&input_num);
    }
    if((pid1=fork())<0){
        printf("fork error");
    }
    else if(pid1==0){
        printf("\nI am the child process,my PID is %d.\n\nThe first %d numbers of fibonacci sequence is:\n", getpid(),input_num);
        for (int i=0;i<input_num;i++)
        {printf("%d\n", fac(i+1));}
    }
    else{
        wait(&child_ret);
        printf("\nI am the parent process,my PID is %d.\n\n", getpid());
    }
    return 0;
}
int fac(int n)
{
    if (n<=2) return n-1;
    else 
    {
        return fac(n-1)+fac(n-2);
    }
}

В этой программе fork сделает копию и вернет два значения. Мы назвали скопированный процесс родительским процессом, а другой дочерним процессом. Если мы вызовем функцию exec(), весь процесс будет заменен новой программой, кроме PID.

CreateProcess():

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

void _tmain( VOID )
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPTSTR szCmdline=_tcsdup(TEXT("MyChildProcess"));

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Start the child process.
    if( !CreateProcess( NULL,   // No module name (use command line)
       szCmdline,      // Command line
       NULL,           // Process handle not inheritable
       NULL,           // Thread handle not inheritable
       FALSE,          // Set handle inheritance to FALSE
       0,              // No creation flags
       NULL,           // Use parent's environment block
       NULL,           // Use parent's starting directory
       &si,            // Pointer to STARTUPINFO structure
       &pi )           // Pointer to PROCESS_INFORMATION structure
       )
    {
       printf( "CreateProcess failed (%d)./n", GetLastError() );
       return;
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Close process and thread handles.
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
}

Это пример из MSDN. То, что мы вызываем для создания нового процесса, должно быть отдельной программой *.exe в системе Windows. Новый процесс — это совершенно новый процесс, который имеет единственную связь возвращаемого значения со старым.
В заключение, мы часто видим fork()+exec() как CreateProcess(). На самом деле fork() больше похоже на CreateThread() в Windows.

person ChaosCosmos    schedule 13.03.2014