Linux-linux和windows创建新进程的区别以及posix_spawn

Linux上创建一个新的进程可以使用fork函数,这个函数执行的效果是复制当前进程创建一个新的进程,这个进程执行的代码与父进程相同。通过fork返回的pid我们可以在fork后的代码中区分父进程和子进程需要执行的逻辑。示例代码如下:

c 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    pid_t pid = fork();
    
    if (pid < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程代码
        printf("Child process (PID: %d)\n", getpid());
    } else {
        // 父进程代码
        printf("Parent process (PID: %d), Child PID: %d\n", getpid(), pid);
    }
    return 0;
}

而在window上,使用CreateProcess接口可以直接指定一个可执行程序路径创建新的进程,新进程的执行代码不在父进程中。

cpp 复制代码
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

void _tmain( int argc, TCHAR *argv[] )
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

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

    if( argc != 2 )
    {
        printf("Usage: %s [cmdline]\n", argv[0]);
        return;
    }

    // Start the child process. 
    if( !CreateProcess( NULL,   // No module name (use command line)
        argv[1],        // 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 );
}

可以看到两者的不同之处:fork复制当前进程开启新进程,执行的代码都在父进程中,createProcess指定可执行程序从而开启新进程,执行代码的代码在指定的可执行程序中。那么在linux上如何实现类似createProcess的效果呢,一种是fork+exec:

复制代码
pid_t parent = getpid();
pid_t pid = fork();

if (pid == -1)
{
    // error, failed to fork()
} 
else if (pid > 0)
{
    int status;
    waitpid(pid, &status, 0);
}
else 
{
    // we are the child
    execve(...);
    _exit(EXIT_FAILURE);   // exec never returns
}

exec函数族会替换当前的进程映像(process image),我的理解是相当于子进程变成了exec指定的新的可执行程序在执行。还可以使用posix_spawn函数,用法类似windows的createProcess:

cpp 复制代码
pid_t pid;
  char *argv[] = {"ls", (char *) 0};
  int status;
  puts("Testing posix_spawn");
  fflush(NULL);
  status = posix_spawn(&pid, "/bin/ls", NULL, NULL, argv, environ);
  if (status == 0) {
    printf("Child id: %i\n", pid);
    fflush(NULL);
    if (waitpid(pid, &status, 0) != -1) {
      printf("Child exited with status %i\n", status);
    } else {
      perror("waitpid");
    }
  } else {
    printf("posix_spawn: %s\n", strerror(status));
  }

Linux设计上将"创建一个新进程"和"加载新的可执行程序到新的进程"两个步骤分离了,而windows的CreateProcess则是把两个步骤合并了。

  1. https://learn.microsoft.com/en-us/windows/win32/procthread/creating-processes
  2. https://stackoverflow.com/questions/5883462/linux-createprocess
  3. https://superuser.com/questions/1737519/why-a-fork-is-often-followed-by-an-exec
相关推荐
Decay__5 分钟前
03_MySQL 存储引擎与存储管理 —— InnoDB 深入、表空间/ibd、binlog/redo/undo 与双写缓冲
运维·数据库·sql·mysql·架构
Z21-X9 分钟前
云原生运维笔记:打通OpenStack的任督二脉——从Neutron网络踩坑到Swift与Heat硬核实战
运维·笔记·学习·云原生
C++ 老炮儿的技术栈14 分钟前
Linux 动态库踩坑:明明重新编译了 .so,调用函数返回值却一直不变(libfjrobot.so 版本号异常排查实录)
linux·c语言·网络·c++·visual studio
你看我名字1 小时前
云计算工程师技能树:从 Linux 基础到云平台架构能力
linux·架构·云计算
懂点Tech8 小时前
ctfshow misc28:GIF 高度修改解题与脚本实现
开发语言·windows·python
广州灵眸科技有限公司8 小时前
4G 模组开机自连 systemd 服务方案:基于灵眸科技EAI1106--Core-T
运维·服务器·科技
天远数科10 小时前
零信任架构实战:基于天远企业股权变更构建自动化商业银行对公授信存续期股权异动与资产抽逃预警网关
运维·人工智能·架构·自动化
qq_4017004110 小时前
Linux设备树详解
linux·运维·服务器
云梦谭10 小时前
让 Linux 主动连接 Windows:配置 Windows 11 SSH 服务端
linux·windows·ssh
奇树谦10 小时前
Windows CMD 下 mc 运维指南:SeaweedFS 安装验收与 MinIO 数据迁移
运维·windows