DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

 

 

一、创建子进程

  • windows系统
BOOL CreateProcess(  
 LPCTSTR lpApplicationName, // 应用程序名称  
 LPTSTR lpCommandLine, // 命令行字符串  
 LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程的安全属性  
 LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程的安全属性  
 BOOL bInheritHandles, // 是否继承父进程的属性  
 DWORD dwCreationFlags, // 创建标志  
 LPVOID lpEnvironment, // 指向新的环境块的指针  
 LPCTSTR lpCurrentDirectory, // 指向当前目录名的指针  
 LPSTARTUPINFO lpStartupInfo, // 传递给新进程的信息  
 LPPROCESS_INFORMATION lpProcessInformation // 新进程返回的信息  
);
  • Linux系统
    popen()会调用fork()产生子进程
FILE * popen( const char * command,const char * type);

二、demo

1、父进程

  • main.cpp
#include<iostream>
#include<windows.h>
using namespace std;
int main(int argc, char*argv[])
{
    cout << "i am father process" << endl;

    STARTUPINFO si = { sizeof(STARTUPINFO) };//在产生子进程时,子进程的窗口相关信息
    PROCESS_INFORMATION pi;                  //子进程的ID/线程相关信息
    DWORD returnCode;//用于保存子程进的返回值;
 
    // char commandLine[] = "C:\\Users\\jx\\Desktop\\test01\\lib\\Debug\\childprocess.exe -l";  //测试命令行参数一
    char commandLine[] = "childprocess.exe -l a b c";  //测试命令行参数一
 
    BOOL bRet = CreateProcess(              //调用失败,返回0;调用成功返回非0;
        NULL,                               //一般都是空;(另一种批处理情况:此参数指定"cmd.exe",下一个命令行参数 "/c otherBatFile")
        commandLine,                        //命令行参数         
        NULL,                               //_In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,
        NULL,                               //_In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,
        FALSE,                              //_In_        BOOL                  bInheritHandles,
        CREATE_NEW_CONSOLE,                 //新的进程使用新的窗口。
        NULL,                               //_In_opt_    LPVOID                lpEnvironment,
        NULL,                               //_In_opt_    LPCTSTR               lpCurrentDirectory,
        &si,                                //_In_        LPSTARTUPINFO         lpStartupInfo,
        &pi);                               //_Out_       LPPROCESS_INFORMATION lpProcessInformation
 
    if (0 != bRet)
    {
        std::cout << "Create Child Process sucess!" << std::endl;
        //等待子进程结束
        WaitForSingleObject(pi.hProcess, -1);
        std::cout << "Child Process is finished"  << std::endl;
        //获取子进程的返回值
        GetExitCodeProcess(pi.hProcess, &returnCode);
        std::cout << "Child Process return code:" << returnCode << std::endl;
    }
    else
    {
        std::cout << "Create child Process error!"<<std::endl;
        return 0;
    }
 
	system("pause");
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    return 0;
}
  • CmakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)
PROJECT(process)
ADD_EXECUTABLE(process main.cpp)
ADD_SUBDIRECTORY(childprocess)
SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")

2、子进程

  • main.cpp
#include<iostream>
using namespace std;
int main(int argc,char* argv[])
{
    std::cout << "i am a child process." << std::endl;

    if (argc>= 2)
    {
        
        int paramID = 0;
        while (paramID < argc-1)
        {
            cout << argv[paramID] << endl;
            paramID++;
        }
        std::cout << "sucess:the return code will be 0" << std::endl;
		system("pause");
        return 0;
    }
    else
    {
        std::cout << "failed:the return code will be -1" << std::endl;
		system("pause");
        return -1;
    }
}
  • CmakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)

SET(TARGET "childprocess")

ADD_EXECUTABLE(childprocess main.cpp)

SET(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")
SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")

三、构建、编译、运行

  • 1、构建

cmake -B build

  • 2、编译

cmake --build build

3、运行

  • 父进程输出

  • 子进程输出

四、相关知识介绍

1、CreateProcess 参数介绍

CreatProcess()需要若干参数来指定新进程的运行方式,但实际使用中多半参数都是用不到的,可以设置为NULL

1.1、lpApplicationName

  • 该参数的类型是LPCTSTR,其实就是一个const char*的传统C字符串,
  • 实际使用中常常把lpApplicationName设置为Null,lpCommandLine参数来指定可执行文件名

1.2、lpCommandLine

  • 该参数的类型是LPTSTR,即一个以’0’结尾的char*的C传统字符串
  • 这个参数用于指定传递给新进程的命令行参数,更多时候我们把可执行文件名也包含在内(这意味着lpApplicationName应该设置为Null)
  • 如果lpApplicationName不为Null,那lpCommandLine就会原封不动的作为命令行参数传递,所以当指定了lpApplicationNAme后就不应该再在lpCommandLine中写可执行文件名了

1.3、lpProcessAttributes

  • 进程对象设置安全性,即返回的新进程对象句柄能否被子进程继承。
  • 一般传递NULL,让windows把进程内核对象设为默认安全性(默认不能被继承)

1.4、lpThreadAttributes

  • 进程对象设置安全性,
  • 一般也传递NULL设置为默认安全性,也就是句柄不能被继承,

1.5、bInheritHandles

  • 这个同样是关于安全性的标识符,是个BOOL型变量,用于控制新进程是否可以从调用进程处继承所有可继承的句柄,

1.6、dwCreationFlags

这是个DWORD的标识,用于设置新进程创建的方式

CREATE_NEW_CONSOLE //要求系统为新进程创建一个新的控制台窗口(否则会和原进程共用一个控制台窗口)
CREATE_NO_WINDOW //不为新进程创建窗口,可以用这个来创建一个没有窗口的应用程序
DEBUG_PROCESS //将新进程作为被调试程序而原进程被当做调试器,新进程和其创建的其他进程中发生的特定事件都会被通知原进程
CREATE_UNICODE_ENVIRONMENT //告诉系统新进程的环境块包含Unicode字符(默认为ANSI)

1.7、lpEnvironment

这个参数指向一块包含新进程要使用的环境字符串的内存,通常传入NULL表示继承原进程的环境字符串,

1.8、lpCurrentDirectory

  • 该参数用于设置新进程的当前驱动器和目录,必须是一个以’0’结尾的绝对路径字符串,如果用不到特殊设置可以直接传递NULL表示新进程的工作目录和创建新进程的原进程工作目录一致,一般就用NULL。

1.9、lpStartupInfo

这个参数指向一个STARTUPINFO或STARTUPINFOEX的结构,一般应用程序会期待仅使用默认值,所以大可以全部置零

1.10、lpProcessInformation

  • 输出参数,指向一个 PROCESS_INFORMATION 结构,返回被创建进程的信息。

typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION,*LPPROCESS_INFORMATION;

分别是进程句柄、线程句柄、进程ID和线程ID

  • 每创建一个新进程都会产生一个进程内核对象和一个线程内核对象,前两个参数就是对应的进程对象的句柄和主线程对象的句柄,而每一个进程和线程windows都会分配一个独一无二的标识符,后两个参数就对应创建的进程的ID和进程的主线程的ID

  • 通常情况下我们会忽略进程ID和线程ID,一般使用相应的句柄进行跟踪控制,如果一定要使用ID的话应该注意一件事:系统中ID是可重用的,这意味着当一个进程或线程终止后同一个ID会分配给其他的新进程或线程,应当及时更新ID,避免出错.

  • 一个进程可以有多个进程句柄,但是只有一个进程id。

  • 进程句柄和现场句柄不再使用时,建议关闭。
    handle(进程句柄表中的索引),这是指向对象的间接指针(在您的具体情况下,ETHREAD)。如果没有关闭,则句柄-对象(ETHREAD)将不是空闲的(直到您的进程终止,并且所有句柄都将关闭)参考进程终止后是否需要关闭线程句柄?

2、int main(int argc, char*argv[])

main 函数的参数只能有两个,还规定 argc 是整型变量,argv 是指向字符串的指针数组。

  • 2.1、argc 是命令行总的参数个数。
  • 2.2、char *argv[ ] 是指针数组,数组中的每个元素都是 char * 类型,即数组中每个元素都会指向一个字符串。从本文demo可以看到,子进程的argv就是父进程传递进来的lpCommandLine。

五、进程相关的API

Windows多进程编程

参考
1、链接: WinAPI执行外部程序和创建新进程:CreateProcess()的使用
2、链接: Windows多进程编程
3、链接: windows下创建进程,CreateProcess()详解及用法

 
posted on   DoubleLi  阅读(2075)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2014-03-16 source code analyzer 功能强大的C/C++源代码分析软件 Celerity CRACK 破解版
2014-03-16 分析函数调用关系图(call graph)的几种方法
2014-03-16 用CodeViz绘制函数调用关系图(call graph)
2014-03-16 C++的辅助工具介绍
2013-03-16 位运算中的异或运算 .
2013-03-16 按位与、或、异或等运算方法
2012-03-16 Javascript 对象用法
点击右上角即可分享
微信分享提示