stdafx.* 句柄 和 ID (转)

本文详细解释了句柄和ID的概念及其在编程中的应用。通过理解这些基础概念,读者可以更好地掌握程序中资源管理和对象引用的方法。
stdafx.* 句柄 和 ID (转)[@more@]

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-990610/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-990610/

内容概要:本文介绍了一种基于蒙特卡洛模拟拉格朗日优化方法的电动汽车充电站有序充电调度策略,重点针对分时电价机制下的分散式优化问题。通过Matlab代码实现,构建了考虑用户充电需求、电网负荷平衡及电价波动的数学模【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺拉格朗日的电动汽车优化调度(分时电价调度)(Matlab代码实现)型,采用拉格朗日乘子法处理约束条件,结合蒙特卡洛方法模拟大量电动汽车的随机充电行为,实现对充电功率时间的优化分配,旨在降低用户充电成本、平抑电网峰谷差并提升充电站运营效率。该方法体现了智能优化算法在电力系统调度中的实际应用价值。; 适合人群:具备一定电力系统基础知识Matlab编程能力的研究生、科研人员及从事新能源汽车、智能电网相关领域的工程技术人员。; 使用场景及目标:①研究电动汽车有序充电调度策略的设计与仿真;②学习蒙特卡洛模拟与拉格朗日优化在能源系统中的联合应用;③掌握基于分时电价的需求响应优化建模方法;④为微电网、充电站运营管理提供技术支持决策参考。; 阅读建议:建议读者结合Matlab代码深入理解算法实现细节,重点关注目标函数构建、约束条件处理及优化求解过程,可尝试调整参数设置以观察不同场景下的调度效果,进一步拓展至多目标优化或多类型负荷协调调度的研究。
// 实验一创建进程.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <iostream> #include <stdio.h> //创建子进程,与父进程执行相同的程序。 void StartClone(int nCloneID) { // 获取当前进程的可执行文件名。 TCHAR szFilename[MAX_PATH] ; :: GetModuleFileName( NULL, //一个模块的句柄。模块句柄跟一般的句柄不一样, //模块句柄指向的就是EXEDLL等在虚拟地址空间的位置。 //如果该参数为NULL,该函数返回该应用程序全路径。 szFilename, MAX_PATH) ; // 格式化用于创建新进程的命令行,包括EXE文件名克隆ID TCHAR szCmdLine[MAX_PATH]; :: sprintf(szCmdLine,"\"%s\"%d",szFilename,nCloneID); // 用于新进程的STARTUPINFO结构 STARTUPINFO si; :: ZeroMemory(reinterpret_cast <void*> (&si) , sizeof(si) ) ; si.cb = sizeof(si) ; // 必须是本结构的大小 // 返回的用于新进程的进程信息 PROCESS_INFORMATION pi; // 使用同一可执行文件带有克隆ID的命令行创建新进程。 BOOL bCreateOK=::CreateProcess( szFilename, // 新进程的可执行文件名 szCmdLine, // 传给新进程的命令行参数 NULL, // 缺省的进程安全性 NULL, // 缺省的线程安全性 FALSE, // 不继承句柄 CREATE_NEW_CONSOLE, // 使用新的控制台 NULL, // 新的环境 NULL, // 当前目录 &si, // 启动信息 &pi) ; // 返回的进程信息 //不使用的句柄最好关掉 if (bCreateOK) { :: CloseHandle(pi.hProcess) ; :: CloseHandle(pi.hThread) ; } } int main(int argc, char* argv[] ) { // 进程的克隆ID int nClone(0) ; //第一个进程argc为1,以后每个进程命令行有两个参数, //其中第二个是克隆ID。 if (argc > 1) { // 从第二个参数中提取克隆ID :: sscanf(argv[1] , "%d" , &nClone) ; } // 显示进程的克隆ID std :: cout << "Process ID:" << :: GetCurrentProcessId() << ", Clone ID:" << nClone << std :: endl; // 创建新进程,其nClone为1-8 const int c_nCloneMax=8; if (nClone < c_nCloneMax) { :: Sleep(1000) ; StartClone(nClone+1) ; } // 等待输入一个字符,以便观察。输入一个字符后,程序结束。 std::cout<<"input a char:"; getchar(); std::cout<<"I'm stopped ... Bye-Bye"; return 0; } /* 思考题: 1.main函数的两个参数如何使用? 2.main函数是如何运行起来的? 3.运行后在系统任务管理器中查看所创建进程映像名是否相同? 4.父子进程运行同一可执行文件,如何能够区分出他们? 5.不同进程的克隆ID是如何获取到的? 6.如果在克隆ID为0的进程中创建克隆ID为1-8的进程,应该如何修改程序? */
11-17
<think> 我们有一个C++程序,它创建了多个进程实例。每个进程都会打印自己的进程ID一个克隆ID(从0开始)。程序会递归地创建最多8个进程(克隆ID从0到7,然后创建克隆ID为8的进程后停止创建)。每个进程在创建下一个进程之前等待1秒,然后等待用户输入一个字符后退出。 程序的工作流程: 1. 主函数main接收命令行参数。如果参数数量大于1,则第二个参数是克隆ID(字符串形式),将其换为整数。 2. 打印当前进程的ID克隆ID。 3. 如果当前克隆ID小于8,则休眠1秒后调用StartClone函数创建下一个克隆(克隆ID+1)。 4. StartClone函数获取当前可执行文件的路径,然后构建命令行,将克隆ID作为参数传递给新进程。 5. 使用CreateProcess创建新进程,新进程会运行同一个可执行文件,并传入新的克隆ID作为参数。 注意:在CreateProcess调用中,我们指定了CREATE_NEW_CONSOLE,所以每个进程会在新的控制台窗口运行。 思考题解答: 1. main函数的两个参数如何使用? main函数的两个参数:argc(参数个数)argv(参数数组)。在这个程序中,第一个参数argv[0]是可执行文件的路径,如果argc>1,则argv[1]是克隆ID(字符串形式)。程序通过sscanf将字符串换为整数nClone。 2. main函数是如何运行起来的? 程序从main函数开始执行,这是C/C++程序的入口点。当操作系统启动进程时,会调用main函数。 3. 运行后在系统任务管理器中查看所创建进程映像名是否相同? 是的,所有进程都是同一个可执行文件的实例,因此映像名相同。 4. 父子进程运行同一可执行文件,如何能够区分出他们? 通过命令行参数传递的克隆ID来区分。每个进程打印的克隆ID不同。 5. 不同进程的克隆ID是如何获取到的? 从命令行参数中获取。第一个进程(克隆ID为0)没有额外的命令行参数,所以它使用默认值0。然后它创建下一个进程并传递1作为参数,依此类推。 6. 如果在克隆ID为0的进程中创建克隆ID为1-8的进程,应该如何修改程序? 目前程序是递归创建:每个进程创建一个子进程(直到达到8)。如果要在克隆ID为0的进程中直接创建1-8的所有进程,可以将递归改为循环。例如,在克隆ID为0的进程中,循环8次,每次创建一个子进程(克隆ID分别为1到8),然后等待用户输入。 修改程序(将递归创建改为在克隆0中循环创建1-8): 我们只需要修改main函数中创建进程的部分。当nClone为0时,我们循环创建克隆ID为1到8的进程,而不是只创建nClone+1(即1)然后递归。 修改后的main函数片段(只修改了创建进程的部分): 我们将递归创建改为:当nClone为0时,循环创建1到8的克隆进程;而其他克隆ID(非0)则不创建子进程(或者根据需求,也可以不修改非0的行为,但原程序是非0也会继续创建,直到8)。但是题目要求是在克隆ID0中创建1-8,所以非0的进程不需要再创建子进程。 修改后的代码: 在main函数中,我们判断如果当前nClone为0,则循环创建1到8的克隆进程。注意,为了避免递归,我们不再让每个子进程继续创建下一个,而是只在0号进程创建所有其他进程。 但是注意:原程序是每个进程创建一个子进程,然后子进程再创建下一个,形成链式。现在要求0号进程直接创建8个子进程(克隆ID1到8)。修改如下: 原代码: if (nClone < c_nCloneMax) { :: Sleep(1000) ; StartClone(nClone+1) ; } 修改为: if (nClone == 0) { for (int i = 1; i <= c_nCloneMax; i++) { StartClone(i); // 为了避免同时创建多个进程导致控制台同时输出混乱,可以加一点延迟 ::Sleep(1000); } } 注意:这样修改后,只有0号进程会创建1到8的进程,而其他进程(1-8)不会创建子进程。 但是原程序中的c_nCloneMax是8,所以当nClone==0时,我们创建1到8(包括8)的进程。注意原程序的条件是nClone<8才创建,所以最多创建到7,然后7创建8。现在0直接创建1-8(8个进程)。 另外,原程序中的c_nCloneMax是8,我们循环从1到8(包括8),所以循环条件为i<=c_nCloneMax。 但是注意,原程序在StartClone函数中创建进程时,新进程会执行同一个可执行文件,并传入克隆ID作为参数。所以这样修改后,0号进程会创建8个子进程,每个子进程的克隆ID分别为1,2,...,8。 修改后的完整代码: </think>以下是对您提供的C++进程创建代码的分析、解释及改进建议: ### 代码功能解析 1. **程序功能**: - 主进程创建一系列子进程(最多8个) - 每个进程打印自己的进程ID克隆ID - 父子进程共享相同的可执行文件 2. **关键函数解析**: ```cpp void StartClone(int nCloneID) { // 获取当前可执行文件路径 TCHAR szFilename[MAX_PATH]; ::GetModuleFileName(NULL, szFilename, MAX_PATH); // 构造命令行参数(包含克隆ID) TCHAR szCmdLine[MAX_PATH]; ::sprintf(szCmdLine, "\"%s\" %d", szFilename, nCloneID); // 初始化进程启动信息 STARTUPINFO si = {0}; si.cb = sizeof(si); // 进程创建信息结构 PROCESS_INFORMATION pi; // 创建新进程 BOOL bCreateOK = ::CreateProcess( szFilename, // 可执行文件路径 szCmdLine, // 命令行参数 NULL, // 进程安全属性 NULL, // 线程安全属性 FALSE, // 不继承句柄 CREATE_NEW_CONSOLE, // 创建新控制台 NULL, // 环境变量 NULL, // 当前目录 &si, // 启动信息 &pi // 进程信息 ); // 关闭未使用的句柄 if (bCreateOK) { ::CloseHandle(pi.hProcess); ::CloseHandle(pi.hThread); } } ``` ### 思考题解答 1. **main函数参数使用**: - `argc`:参数数量(第一个参数总是程序路径) - `argv[1]`:存储传入的克隆ID(字符串类型) - 使用`sscanf`将字符串换为整数:`::sscanf(argv[1], "%d", &nClone)` 2. **main函数运行机制**: - 操作系统加载可执行文件后,由C/C++运行时库调用main - 运行时库处理环境设置、全局初始化等工作 - 入口点函数(如`mainCRTStartup`)最终调用main 3. **进程映像名**: - 所有进程都运行同一可执行文件 - 任务管理器中将显示相同的映像名称 4. **进程区分方法**: - 通过命令行传入的克隆ID区分 - 每个进程打印不同的克隆ID值 - 进程ID(PID)由操作系统分配,各不相同 5. **克隆ID获取**: ```cpp if (argc > 1) { ::sscanf(argv[1], "%d", &nClone); } ``` - 父进程通过命令行参数传递克隆ID - 子进程解析argv[1]获取克隆ID 6. **批量创建进程修改**: ```cpp // 修改main函数中的创建逻辑 if (nClone == 0) { for (int i = 1; i <= c_nCloneMax; ++i) { StartClone(i); ::Sleep(100); // 避免同时创建导致资源冲突 } } ``` ### 改进建议 1. **错误处理增强**: ```cpp if (!bCreateOK) { DWORD err = ::GetLastError(); std::cerr << "CreateProcess failed. Error: " << err << std::endl; } ``` 2. **参数安全验证**: ```cpp if (argc > 1) { if (::strlen(argv[1]) < 3) // 防止缓冲区溢出 ::sscanf(argv[1], "%d", &nClone); } ``` 3. **进程树可视化**: ```cpp // 添加进程层级显示 std::cout << "Process tree: "; for (int i = 0; i < nClone; ++i) std::cout << "->"; std::cout << "PID:" << ::GetCurrentProcessId() << std::endl; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值