forking()和CreateProcess(带有所有必需的参数),Linux和WinXP分别是一样的吗?
如果它们不同,那么有人可以解释两种情况中每种情况的差异吗?
谢谢
他们在不同的系统上做不同的事情。 CreateProcess
是一个仅限Windows的功能,而fork
仅适用于POSIX(例如Linux和Mac OSX)系统。
fork
系统调用创建一个新进程,并从调用fork
函数的点继续执行父进程和子进程。 CreateProcess
创建一个新进程并从磁盘加载程序。唯一的相似之处是最终结果是创建了一个新流程。
有关更多信息,请阅读CreateProcess
和fork
上的相应手册页。
CreateProcess采取以下步骤:
Unix的fork采取以下步骤:
它创建父进程的完整副本,而父进程没有为子进程设置运行时环境,因为父进程信任自己的设置。子进程是父进程的完整副本,但进程ID除外(fork返回)。分叉进程继续运行与其父进程相同的程序,直到它执行显式exec。当子调用exec时,新的可执行映像进入内存并运行。
制作完整的副本效率如何?写入时复制。它实际上只复制虚拟内存映射。段表中的所有段都是只读的。如果父节点或子节点编辑段中的数据,则抛出异常并且内核创建该节点的完整内存副本。在这个answer中很好地解释了这一点
父子之间共享资源有几个好处: - 直观地说,资源管理:维护进程状态需要更少的内存 - 共享缓存资源意味着当数据未被写入时数据的时间局部性更大,从而提高了性能因为从较大的缓存/磁盘中检索数据非常耗时。
共享资源的缺点: - 当写入很常见时,它会将数据置于其他进程的无效状态,这会导致一致性错失,如果子进程在单独的核心上运行,则代价很高,因为这些更改将不得不传播到L3缓存。
一般来说,程序读取的内容比写入要多得多,通常子/父只需要写入其堆栈,这只是程序块的一小部分。
另外Unix fork是不同的,因为它返回两次,一次在父级(其子级的进程ID),一次在子级(0,恭喜你是一个新的婴儿进程),这就是我们在代码中区分的方式,如果我们是孩子还是父母。
Unix Exec执行以下操作:
父母可以选择等待孩子完成。当孩子完成时,调用退出时是通知父母的等待。
我将举两个例子来说明差异:
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()
更相似。