forking()和CreateProcess()

8

在Linux和WinXP中,fork()和CreateProcess(带有所有必要的参数)是否是相同的东西?

如果它们不同,那么有人能解释一下在每种情况下会发生什么吗?

谢谢

3个回答

10
它们执行不同的任务,运行于不同的系统。CreateProcess是仅适用于Windows的函数,而fork则只能在POSIX(例如Linux和Mac OSX)系统上使用。 fork系统调用创建一个新进程,并在父进程和子进程中从调用fork函数的点继续执行。 CreateProcess创建一个新进程并从磁盘加载程序。唯一相似之处是最终结果是创建了一个新进程。
有关更多信息,请阅读 CreateProcessfork 的各自手册页面。
总结一下:CreateProcessfork()exec()函数的组合类似。

8

CreateProcess 进行以下步骤:

  • 在内核中创建和初始化进程控制块(PCB)。
  • 创建和初始化新的地址空间。
  • 将程序 prog 加载到地址空间中。
  • 将参数 args 复制到地址空间中的内存中。
  • 初始化硬件上下文以在“start”处开始执行。
  • 通知调度程序新进程已准备好运行。

Unix 的 fork 进行以下步骤:

  • 在内核中创建和初始化进程控制块(PCB)。
  • 创建一个新的地址空间。
  • 使用父进程的地址空间的完整内容来初始化地址空间。
  • 继承父进程的执行上下文(例如,任何打开的文件)。
  • 通知调度程序新进程已准备好运行。
它创建了父进程的完整副本,父进程不为子进程设置运行时环境,因为父进程信任自己的设置。子进程是父进程的完整副本,除了其进程ID(fork返回值)。分叉进程继续运行与其父进程相同的程序,直到执行显式exec操作。当子进程调用exec时,将新的可执行镜像加载到内存并运行。
如何高效地进行完整复制?写时复制。它实际上只复制虚拟内存映射。段表中的所有段都是只读的。如果父进程或子进程编辑段中的数据,则会抛出异常,并且内核会创建该数据的完整内存副本。这在answer中很好地解释了。
共享父子进程之间的资源有几个好处: - 直观上,资源管理:需要较少的内存来维护进程状态 - 缓存资源是共享的,意味着当数据未被覆盖时具有更大的时间局部性,这提高了性能,因为从较大的缓存/磁盘检索数据是耗时的。
缺点是共享资源: - 当写操作很常见时,它会使其他进程的数据处于无效状态,这导致一致性丢失,如果子进程在单独的核心上运行,则代价很高,因为更改将需要传播到L3缓存。

总的来说,程序通常读取的比写入要多得多,通常子/父进程只需要对其堆栈进行写入,而这只是他们程序块的一小部分。

此外Unix fork不同之处在于返回两次,一次在父进程中(其子进程的进程ID),一次在子进程中(0,恭喜你成为新的子进程),这是我们在代码中区分自己是子进程还是父进程的方式。
Unix Exec执行以下操作:
  • 将程序prog加载到当前地址空间中。
  • 将参数args复制到地址空间中的内存中。
  • 初始化硬件上下文以在“start”处开始执行。
父进程有等待子进程完成的选项。当子进程完成并调用exit时,父进程的wait将被通知。

1
我将给出两个示例来展示区别:
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 的一个示例。在 Windows 系统中,我们所谓的创建新进程必须是一个单独的 *.exe 程序。新进程是一个全新的进程,只与旧进程有返回值的唯一连接。
总之,我们经常将 fork() + exec() 视为 CreateProcess()。实际上,fork() 更类似于 Windows 中的 CreateThread()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接