Windows并发&异步编程(0)创建、终止进程

来源:互联网 发布:王蕙玲编剧知乎 编辑:程序博客网 时间:2024/06/06 05:51

上大学那会,知道进程是分配资源的最小单位,而线程是处理机分配的最小单位(执行最小单位)。很多时候创建进程是一种极大的浪费,但是有时候创建进程是必要的。一种很常见的情况,在程序运行时,需要运行一个其他的exe程序,这时候可以创建进程,Windows中使用CreateProcess创建一个进程….


目录:

  • 扒一下CreateProcess
  • 创建进程
    • 初始化参数
    • Wait child process
    • 关闭句柄
  • 终止进程
  • 简单DEMO

扒一下CreateProcess

Windows下,这个创建进程API,参数还是蛮多的。

CreateProcess(_In_opt_ LPCSTR lpApplicationName,  //demo.exe_Inout_opt_ LPSTR lpCommandLine,    //param1 param2_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,//NULL,不继承进程句柄_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //NULL,不继承线程句柄_In_ BOOL bInheritHandles,          //FALSE,不继承句柄_In_ DWORD dwCreationFlags,         //0,无标识[0,CREATE_NEW_CONSOLE,DEBUG_PROCESS]_In_opt_ LPVOID lpEnvironment,      //NULL,使用父环境变量_In_opt_ LPCSTR lpCurrentDirectory, //NULL,使用父进程路径作为当前目录_In_ LPSTARTUPINFOA lpStartupInfo,  //NULL,无启动信息_Out_ LPPROCESS_INFORMATION lpProcessInformation //[out]保存了进程信息);

上面这个是从VS2013中拷贝出来的,后面的注释是参考了《精通Windows API——函数、接口、编程实例》一书。

需要吐槽一下,

  • CREATE_NEW_CONSOLE ,这个命令会弹出一个新DOS界面,运行新进程。如果直接传入0,那么就在同一个DOS界面跑父子进程了。
  • CreateProcess ,如果他返回值是2,说明你的demo.exe路径写错了。

创建进程

参数虽多,使用起来却异常简单,不明确的我一律传NULL,反正不影响功能。以后如果要深入研究上下文的时候,再进一步分析。

初始化参数

PROCESS_INFORMATION 这个结构体,在进程中是异常重要的,它保存了进程N多的信息,HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; 都在这个结构体中…

STARTUPINFO si;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);PROCESS_INFORMATION pi;ZeroMemory(&pi, sizeof(pi));
  • STARTUPINFO是一个保存启动信息的结构体;
  • ZeroMemory顾名思义,将内存初始化为0;
  • PROCESS_INFORMATION 保存了进程信息,可以看成PCB?就是进程控制块。当然不可以啦,它只是简单的摘录了一些Windows暴露出来的进程信息。
  • GetLastError(),可以很方便的获取上一步的错误值。

Wait child process

每个进程的奔跑速度并不是我们想象中的那样,难道执行100次循环的进程,就一定比执行99次循环的进程运行的慢吗?为了很好的控制多个进程的运行关系,Windows有个等待机制,

  • WaitForSingleObject ,等待单个对象,有两个参数:
    • HANDLE hHandle,对象的句柄。这里需要简单谈一下句柄,由于Windows运行时分为核心态和用户态,像进程管理,这些很important的事情,Windows是不会让我们这些凡人触碰的。它自己全权管理。但是我们这些凡人有需要使用进程,怎么办?很简单,Windows给他每个东东都分配了一个句柄(也叫作身份标识),你们凡人需要什么功能,Windows帮你去拿,拿到之后给你,你只要告诉我你要什么就行了,但不一定给你。就是不让你自己去拿。很显然吧,句柄比指针安全很多。
    • DWORD dwMilliseconds,这就就是等待时长了,单位是毫秒。如果传入-1,那就是理论上的无限等待了,当然-1有个宏叫INFINITE。
WaitForSingleObject(pi.hProcess, INFINITE);CloseHandle(pi.hProcess);CloseHandle(pi.hThread);

Windows等待机制,这只是其中的一部分,它当然不会只有这一个函数。如果我要等待多个进程,那不是要把WaitForSingleObject 执行Ctrl+C/Ctrl+V ,若干次?这是多么糟糕的一个程序。

C语言里面,定义变量可以用int a,b,c,d,e,f; 定义多个变量这样太麻烦了吧?嘿嘿,于是就产生了数组,int arr[5]。多么简洁,Aha….

Windows当然也有WaitForMultipleObjects函数,这里我并不会讲。因为本文还没有用到。感兴趣的可以去《Windows并发&异步编程(1)多线程与JAVA》抢先看。

关闭句柄

CloseHandle是个很神奇的函数,就算你在CreateProcess下一步,立马CloseHandle也不会有任何问题~我说的是真的。

that’s why?

其实啊,CloseHandle 中文名叫 关闭一个内核对象。(就像笔者英文名William Aiden,或者更确切说是笔名哈。)其中包括文件、文件映射、进程、线程、安全和同步对象等。在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。

CloseHandle(pi.hProcess);CloseHandle(pi.hThread);

每个进程中,必定有一个主线程在跑。就像我们的第一个计算机程序,Hello,World!编译之后,会产生一个exe文件,点击运行,就产生了一个进程,而main本身就是一个主线程………..跑啊跑……..跑啊跑….一直到return 0.

若在线程执行完之后,没有调用CloseHandle,在进程执行期间,将会造成内核对象的泄露,相当于句柄泄露,但不同于内存泄露,这势必会对系统的效率带来一定程度上的负面影响。但当进程结束退出后,系统会自动清理这些资源。

终止进程

有一种很粗暴的关机方式,叫做拔电源。TerminateProcess也是一种很粗暴的方式,它是用来终止进程的,这里我并不会去讨论这种粗暴的方式会对内存造成哪些泄露或者是伤害,因为我也还没研究。正是因为这个原因,uExitCode参数我也直接传入了一个0。其实这个exitcode是可以获取的,表示进程当前的状态。

TerminateProcess(    _In_ HANDLE hProcess,    _In_ UINT uExitCode    );

正如线程一样,最自然的方式是让它自己安安静静的走过这一片世界,不要干扰她的生活…

TerminateProcess(pi.hProcess,0);/*终止进程*/

也这样对待进程吧。

Do not to call ‘TerminateProcess’.

简单DEMO

文章底部,粘贴部分Code,是我一贯的风格。万一有人想看呢?其实,我只是写给自己看的。

#include <stdio.h>#include <Windows.h>int main(int argc, char* argv[]){    printf("%s\n",argv[0]);    STARTUPINFO si;    ZeroMemory(&si, sizeof(si));    si.cb = sizeof(si);    PROCESS_INFORMATION pi;    ZeroMemory(&pi, sizeof(pi));    if (!CreateProcess("E:\\VS\\demo\\Debug\\demo.exe", "123 abc", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)){        printf("Create failed(%d).\n",GetLastError());    }    for (int i = 0; i < 3; ++i){        printf("father .................... %d\n", i);        Sleep(500);    }    printf("\n----father finish---\n");    Sleep(2000);    //TerminateProcess(pi.hProcess,0);/*终止进程*/    WaitForSingleObject(pi.hProcess, INFINITE);    CloseHandle(pi.hProcess);    CloseHandle(pi.hThread);    return 0;}
阅读全文
0 0
原创粉丝点击