Windows系统编程(二)进程与线程一

news2024/10/5 3:16:37

进程与线程

进程:直观的讲就是任务管理器中我们看到的东西。

与内核对象句柄相似的,进程也有进程对象句柄,可以进行进程的各种操作如打开关闭。

每个进程都是独立的,在进程启动以后系统分配彼此独立的虚拟内存,此时进程会将其所有的代码等数据在虚拟内存中进行展开

进程本身不能执行代码,它是一种严谨的数据结构,用于进行管理相关工作。其在三环有一个结构叫做PEB,在0环有一个结构叫EPROCESS,这两个结构用于对进程进行管理工作。

一个进程可以有多个线程,它们存储在线程列表中。在如上的两个结构中都有一个项用于指向线程列表,而线程才是真正执行代码的东西

当进程启动时,主线程被启动,用于执行main函数

在单核处理器下,我们看到的多线程同时进行只是多线程在极短的时间内进行快速切换执行的假象,而在多核处理器下,每个核心都可以独立去执行单个线程,是真正意义上的多线程同时执行。

当主线程消失的时候,进程也随之销毁

在Windows下创建进程有多种形式,如WinExec(),system()等等,其本质是对CreateProcess()的封装

现我们通过一个完整的程序了解进程与线程

#include<Windows.h>
#include<iostream>
int main()
{
	//该结构体指定创建进程时的主窗口的窗口工作站,桌面,标准句柄和外观
	STARTUPINFO StartupInfo = { sizeof(STARTUPINFO) };//必须初始化该结构第一个成员cb,即该结构大小。利用sizeof是因为防止因Windows的更新迭代导致该结构发生变化导致结构大小错误
	//该结构体包含有关新创建的进程及其主线程的信息
	PROCESS_INFORMATION ProcessInformation;
	//创建进程
	BOOL bRet = CreateProcess(L"F:\\ChinaNet-EDU.exe",     //文件路径
		NULL,                                 //命令行参数
		NULL,                                 //进程安全属性
		NULL,                                 //主线程安全属性
		FALSE,                                //进程句柄是否可继承
		NULL,                                 //控制优先级类和进程的创建标志
		NULL,                                 //指向新进程的环境块的指针
		NULL,                                 //进程当前目录的完整路径
		&StartupInfo,                         //指向STARTUPINFO或STARTUPINFOA的指针
		&ProcessInformation                   //指向PROCESS_INFORMATION结构的指针
	);
	if (!bRet) {
		std::cout << "CreateProcess Failed!" << std::endl;
	}
	else {
		std::cout << "进程句柄:" << ProcessInformation.hProcess << std::endl;
		std::cout << "线程句柄:" << ProcessInformation.hThread << std::endl;
		std::cout << "进程ID:" << ProcessInformation.dwProcessId << std::endl;
		std::cout << "主线程ID:" << ProcessInformation.dwThreadId << std::endl;
		//CloseHandele(ProcessInformation.hThread);
		//CloseHandele(ProcessInformation.dwThreadId);//不使用句柄时,关闭
	}
	//关闭进程(只能关闭没有保护,即权限较低的进程)
	//TerminateProcess(ProcessInformation.hProcess, 0);
	//通过关闭主线程关闭进程
	TerminateThread(ProcessInformation.hThread, 0);
	//结束当前进程:
	ExitProcess(0);
	system("pause");
	return 0;
}

在上述程序中我们通过了进程句柄去结束我们自己的进程。但当我们想要结束不是我们自己创建的进程/线程时,我们可以通过任务管理器查找进程ID去获取进程句柄

#include<Windows.h>
#include<iostream>
int main()
{
    //如现在我们通过任务管理器得知一个进程ID:5340
    HANDLE hProcesss = OpenProcess
    (
        PROCESS_ALL_ACCESS,   //权限
        FALSE,                //可否继承
        5430                 //进程ID
  	)//获取进程句柄
    if(hProcess==NULL)//当无法打开该进程,即打开不了权限较高的进程时
    {
    	std::cout<<"OpenProcess Error Code:"<<GetLastError<<std::endl;
  	}
    TerminateProcess(hProcess,0);
	return 0;
}

进程快照

在实际的应用中,我们不可能去通过任务管理器去查找进程ID,因为太耗费时间。因此我们可以通过进程快照来获取我们需要的进程ID并进行接下来的操作

#include<Windows.h>
#include<iostream>
#include <TlHelp32.h> //需要包含的头文件
int main()
{  
  	//创建进程快照
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
	//拿到第一个进程信息
	PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
	BOOL bRet = Process32First(hSnap, &pe32);
	//遍历进程快照
    while(bRet) 
    {
		std::cout << pe32.szExeFile << ":" << lppe.th32ProcessID << std::endl;//打印进程名及ID
		//字符串比较
		if (strcmp(pe32.szExeFile, "ChinaNet-EDU.exe") == 0) //当遍历到我们想要打开的进程时
        { 
			//打开进程
			HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
			//关闭进程
			BOOL Ret = TerminateProcess(hProcess, 0);
			if (!Ret) 
            {
				std::cout<<"TerminateProcess:"<<pe32.szExeFile<<"Failed Code :"<<std::endl;
			}
		}
		//继续找下一个进程
		bRet = Process32Next(hSnap, &lppe);
	}
    return 0;
}

线程的开关

//该程序有两个线程,一个主线程一个子线程
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
DWORD ThreadCallBack(LPVOID lpThreadParameter) //此处是我们创建个一个子线程
{
	int i = 0;
	while (true)
	{
		std::cout << "Thread:" << i++ << std::endl;
		Sleep(1000);
	}
}
int main()
{
  	//用于接收线程ID
	DWORD dwThreadID;
	//创建线程
	HANDLE hThread = CreateThread(
		NULL,           //安全属性,结构体里面有一个成员,决定线程句柄是否可以继承
		NULL,           //堆栈大小,如果为NULL,则分配默认大小
		ThreadCallBack, //指向有线程执行的应用程序定义函数的指针
		NULL,           //指向由线程执行的应用程序传给线程的变量指针
		NULL,           //控制线程创建的标志:立即执行或挂起等状态
		&dwThreadID     //指向接收线程表示符的变量指针
	);
	int i = 0;
	while (true)
	{
		std::cout << "Main:" << i++ << std::endl;
		Sleep(1000);
	} 
	system("pause");
	return 0;
}

注意:当主线程关闭时,子线程也随之关闭

作业

1.实现线程快照功能


#include<Windows.h>
#include <iostream>
#include<TlHelp32.h>
int main()
{
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
    if (hSnap == INVALID_HANDLE_VALUE)
    {
        std::cout << "CreateToolhelp32Snapshot failed" << std::endl;
        return FALSE;
    }
    THREADENTRY32 hThread = { sizeof(THREADENTRY32) };
    BOOL bRet = Thread32First(hSnap, &hThread);
    while (bRet)
    {
        std::cout << "ThreadID:" << hThread.th32ThreadID << std::endl;
        bRet = Thread32Next(hSnap, &hThread);
        if (bRet == FALSE)
        {
            std::cout << "线程快照打印完毕" << std::endl;
            CloseHandle(hSnap);
            return FALSE;
        }
    }
    return 0;
}

2.尝试线程的挂起与恢复

#include<Windows.h>
#include<iostream>
#include<thread>
void FirstThread()
{
	std::cout << "FirstThread线程开始" << std::endl;
	int i = 0;
	for (int i = 0; i < 10000; i++)
	{
		std::cout << "i = " << i << std::endl;
	}
}
int main()
{
	std::thread ThreadOne(FirstThread);
	SuspendThread(ThreadOne.native_handle());
	std::cout << "FirstThread被挂起" << std::endl;
	Sleep(3000);
	ResumeThread(ThreadOne.native_handle());
	std::cout << "FirstThread被唤起" << std::endl;
	ThreadOne.join();
	return 0;
}

3.使用MFC制作一个进程管理器(进程LIst)右键可以结束进程,可以打开线程列表(右键结束线程,挂起恢复线程)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2189156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手写mybatis之Mapper XML的解析和注册使用

前言 你是怎么面对功能迭代的&#xff1f; 很多程序员在刚开始做编程或者新加入一家公司时&#xff0c;都没有多少机会可以做一个新项目&#xff0c;大部分时候都是在老项目上不断的迭代更新。在这个过程你可能要学习N个前人留下的各式各样的风格迥异的代码片段&#xff0c;在这…

【杂谈一之概率论】CDF、PDF、PMF和PPF概念解释与分析

一、概念解释 1、CDF&#xff1a;累积分布函数&#xff08;cumulative distribution function&#xff09;&#xff0c;又叫做分布函数&#xff0c;是概率密度函数的积分&#xff0c;能完整描述一个实随机变量X的概率分布 2、PDF&#xff1a;连续型概率密度函数&#xff08;p…

平面电磁波的电场能量磁场能量密度相等,能量密度的体积分等于能量,注意电场能量公式也没有复数形式(和坡印廷类似)

1、电场能量密度和磁场能量密度相等(实数场算的) 下面是电场能量密度和磁场能量密度的公式&#xff0c;注意这可不是坡印廷定理。且电场能量密度没有复数表达式&#xff0c;即不是把E和D换成复数形式就行的。注意&#xff0c;一个矢量可以转化为复数形式&#xff0c;两个矢量做…

数据挖掘-padans初步使用

目录标题 Jupyter Notebook安装启动 Pandas快速入门查看数据验证数据建立索引数据选取⚠️注意&#xff1a;排序分组聚合数据转换增加列绘图line 或 **&#xff08;默认&#xff09;&#xff1a;绘制折线图。bar&#xff1a;绘制条形图。barh&#xff1a;绘制水平条形图。hist&…

Discord:报错:A fatal Javascript error occured(解决办法)

按 Windows 键 R 并输入 %appdata% 选择 discord 文件夹并将其删除。 再次按 Windows 键 R 并输入 %LocalAppData% 选择 discord 文件夹并再次将其删除。 附加&#xff1a; 如果还不行&#xff0c;就通过官网下载吧&#xff0c;这个问题通过epic下载可能会有

图文深入理解Oracle DB企业级集中管理神器-GC的安装和部署

值此国庆佳节&#xff0c;深宅家中&#xff0c;闲来无事&#xff0c;就多写几篇博文。今天继续宅继续写。 本文承接上篇&#xff0c;介绍GC的安装和部署。咱们不急&#xff0c;慢慢来&#xff0c;饭要一口一口地吃才能吃得踏实自然。 限于篇幅&#xff0c;本节将重点介绍关键步…

【ubuntu】apt是什么

目录 1.apt简介 2.常用apt指令 2.1安装 2.2更新列表 2.3更新已经安装的软件包 2.4搜索软件包 2.5显示软件包信息 2.6移除软件包 2.7清理无用的安装包 2.8清理无用的依赖项 3.apt和apt-get 3.1区别 3.2 总结 1.apt简介 apt的全称是advanced package …

JAVA的三大特性-封装、继承、多态

Java作为一种面向对象的编程语言&#xff0c;其核心特性包括封装、继承和多态。这三大特性是Java语言的基石&#xff0c;它们相互关联&#xff0c;共同构成了Java强大的面向对象能力。 封装&#xff08;Encapsulation&#xff09; 封装是面向对象编程的一个重要概念&#xff0c…

Pytorch最最适合研究生的入门教程,Q3 开始训练

文章目录 Pytorch最最适合研究生的入门教程Q3 开始训练3.1 训练的见解3.2 Pytorch基本训练框架work Pytorch最最适合研究生的入门教程 Q3 开始训练 3.1 训练的见解 如何理解深度学习能够完成任务&#xff1f; 考虑如下回归问题 由函数 y f ( x ) yf(x) yf(x)采样得到的100个…

现在的新电脑在任务管理器里又多了个NPU?它是啥?

前言 今年中旬各家品牌的新笔记本感觉上都是很不错&#xff0c;搞得小白自己心痒痒&#xff0c;突然间想要真的买一台Windows笔记本来耍耍了。 但今天这个文章并不是什么商品宣传啥的&#xff0c;而是小白稍微尝试了一下新笔记本之后的一些发现。 在今年的新笔记本上都多了一…

【GESP】C++一级练习BCQM3025,输入-计算-输出-6

题型与BCQM3024一样&#xff0c;计算逻辑上稍微复杂了一点点&#xff0c;代码逻辑没变&#xff0c;仍属于小学3&#xff0c;4年级的题目水平。 题解详见&#xff1a;https://www.coderli.com/gesp-1-bcqm3025/ https://www.coderli.com/gesp-1-bcqm3025/https://www.coderli.c…

数据提取之JSON与JsonPATH

第一章 json 一、json简介 json简单说就是javascript中的对象和数组&#xff0c;所以这两种结构就是对象和数组两种结构&#xff0c;通过这两种结构可以表示各种复杂的结构 > 1. 对象&#xff1a;对象在js中表示为{ }括起来的内容&#xff0c;数据结构为 { key&#xff1…

最新版本SkyWalking【10.1.0】部署

这里写目录标题 前言前置条件启动Skywalking下载解压启动说明 集成Skywalking Agent下载Agent在IDEA中添加agent启动应用并访问SpringBoot接口 说明 前言 基于当前最新版10.1.0搭建skywalking 前置条件 装有JDK11版本的环境了解SpringBoot相关知识 启动Skywalking 下载 地…

浑元换算策略和武德换算策略-《分析模式》漫谈36

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 “Analysis Patterns”的第3章有这么一句&#xff1a; A conversion, however deterministic, does not follow that faithfully. 2004&#xff08;机械工业出版社&#xff09;中译本…

HTB:Explosion[WriteUP]

目录 连接至HTB服务器并启动靶机 1.What does the 3-letter acronym RDP stand for? 2.What is a 3-letter acronym that refers to interaction with the host through a command line interface? 3.What about graphical user interface interactions? 4.What is the…

【MySQL 08】复合查询

目录 1.准备工作 2.多表查询 笛卡尔积 多表查询案例 3. 自连接 4.子查询 1.单行子查询 2.多行子查询 3.多列子查询 4.在from子句中使用子查询 5.合并查询 1.union 2.union all 1.准备工作 如下三个表&#xff0c;将作为示例&#xff0c;理解复合查询 EMP员工表…

深入探究:在双链表的前面进行插入操作的顺序

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd;惟有主动付出&#xff0c;才有丰富的果…

一次解决Go编译问题的经过

用Go语言编写了一个小的项目&#xff0c;项目开发环境是在本地的Windows环境中&#xff0c;一切单元测试和集成测试通过后&#xff0c;计划将项目部署到VPS服务器上自动运行&#xff0c;但在服务器上执行go run运行时&#xff0c;程序没有任何响应和回显&#xff0c;甚至main函…

有没有一款软件,可以在二楼电脑直接唤醒三楼的电脑?

前言 今天有个小姐姐找到我&#xff0c;咨询能不能在二楼的电脑直接访问到三楼电脑的资料。 这个肯定是可以的啊&#xff01; 其实事情很简单&#xff0c;只需要弄好共享文件夹这个功能&#xff0c;只要手机、平板或者电脑在同个局域网下&#xff0c;就能访问到三楼电脑里的…

深入理解Dubbo源码核心原理-Part4

现在开始研究&#xff0c;消费端真正调用proxy的方法时&#xff0c;走的rpc调用 接下来就要走client&#xff0c;发送request请求了 Dubbo协议是怎样的呢&#xff1f; 具体每个字段什么含义请参照官网 链接&#xff1a;Dubbo协议头含义 编码器按照Dubbo协议来进行编码请求 Ne…