操作系统实验:线程的创建与撤销_线程的创建与撤销实验报告-程序员宅基地

技术标签: 操作系统  多线程  多进程  

一、实验目的

(1)熟悉windows系统提供的线程创建与撤销系统调用。
(2)掌握windows系统环境下线程的创建与撤销方法。
(3)掌握CreateThread()函数和ExitThread()函数。 

二、实验准备

(1).实验在windows XP,VC++6.0环境下进行。在这一步,安装了Windows XP虚拟机,学会了创建一个控制台工程文件。

(2).百度句柄的含义:句柄(handle),有多种意义,第一种解释:句柄是一种特殊的智能指针 。当一个应用程序要引用其他系统(如数据库、操作系统)所管理的内存块或对象时,就要使用句柄。句柄是Windows用来标志应用程序中建立的或是适用的对象的唯一整数,Windows大量使用了句柄来标识对象。

(3).参照实验指导学习函数原型--CreateThread()函数:--线程创建
	HANDLE CreateThread(
  		LPSECURITY_ATTRIBUTES   IpThreadAttributes,
  		DWORD                   dwStackSize,
  		LPTHREAD_START_ROUTINE  IpStartAddress,
  		LPVOID 					IpParameter,
  		DWORD                   dwCreationFlags,
  		LPDWORD                 IpThreadId
  	);
	!!!实例化:HANDLE h1 = CreateThread( NULL, 0, Fun1, NULL, 0, NULL );
	<1>.参数IpThreadAttributes指定线程安全属性,当其为NULL时,则线程获取默认安全描述符。
	<2>.参数dwStackSize指定线程堆栈的初始大小,以字节为单位。如果此参数为0,则新线程使用可执行文件的默认大小。
	<3>.参数IpStartAddress指定由线程执行的自定义函数的指针。
	<4>.参数IpParameter指定自定义函数的参数。
	<5>.参数dwCreationFlags指定线程创建后所处的状态。该值为0,表示线程创建后立即执行。
	<6>.参数IpThreadId指定接收线程标识符的变量的指针。该参数为 NULL,则不返回线程标识符。
	---如果函数成功,则返回值是新线程的句柄。如果函数失败,则返回值为NULL。
	
(4).参照实验指导学习函数原型--ExitThread()函数:--撤销进程
	<1>.ExitThread()用于撤销当前进程。
	<2>.该函数没有返回值。
	<3>.用法举例:ExitThread(0);//参数0表示要撤销进程中的所有线程
	
(5).参照实验指导学习函数原型--TerminateThread()函数:--终止线程
	TerminateThread()用于终止当前线程。该函数与ExitThread()的区别在于,ExitThread()在撤销线程时将该线程所拥有的资源全部归还给系统,而TerminateThread()不归还资源。在实验中用ExitThread()函数居多。
	
(6).参照实验指导学习函数原型--Sleep()函数:--挂起线程
	该函数没有返回值。
	
(7).参照实验指导学习函数原型--CloseHandle()函数:--关闭句柄
	返回值:如果函数调用成功,则返回值为非0值;如果函数调用失败,则返回值为0.若要得到更多的错误信息,调用函数GetLastError()查询。

三、实验内容

(一)实验内容
实验1.使用系统调用CreatThread()创建一个子线程,并在子线程中显示;Thread is Running!.为了能让用户清楚地看到线程的运行情况,使用Sleep()使线程挂起5s,之后使用ExitThread(0)撤销进程.

实验2.模仿教学视频中的程序,改写一个吃苹果进程,采用多线程‘吃苹果’与单一线程‘吃苹果’做对比。了解多线程的运行原理。
(二)主要代码:

实验一:

#include "stdafx.h"
#include "01.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

void ThreadName1();
static HANDLE hHandle1=NULL;
DWORD dwThreadID1;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	hHandle1 = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) ThreadName1,
		(LPVOID) NULL,
		0, &dwThreadID1 );
	Sleep(5000);
	CloseHandle(hHandle1);
	ExitThread(0);

	return nRetCode;
}

void ThreadName1()
{
	printf("Thread is running!");
}

实验二:

#include "stdafx.h"
#include "011.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CWinApp theApp;

using namespace std;

void eatApple(int number){
	Sleep((3 - number)*1000);
	printf("I'm eatting #%d apples.\n",number);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	HANDLE h1 = NULL;
	HANDLE h2 = NULL;
	HANDLE h3 = NULL;
	DWORD Th1 = NULL;
	DWORD Th2 = NULL;
	DWORD Th3 = NULL;

	int a=0;
	int b=1;
	int c=2;
	h1 = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) eatApple,
		(LPVOID) a,
		0, &Th1 );
	h2 = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) eatApple,
		(LPVOID) b,
		0, &Th2 );
	h3 = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) eatApple,
		(LPVOID) c,
		0, &Th3 );

	eatApple(a);
	eatApple(b);
	eatApple(c);
	
	ExitThread(0);
	return nRetCode;
}

四、实验结果与总结

实验一总结:
   在Windows系统中进程是资源的拥有者,线程是系统调用的基本单位。  
   进程创建后,其主线程也随即被创建。在该实验中,有创建了一个名为  
   ThreadName1的子线程,该子线程与主线程并并发的被系统调度。  
   为了能让用户清楚地看到线程的运行情况,在主线程创建了子线程之后,  
   将主线程挂起5s,以确保子线程能够运行完毕,
   之后调用ExitThread(0)将所有线程撤销。

在这里插入图片描述
在这里插入图片描述

实验二总结:
   在该实验中,创建了Th1 Th2 Th3三个子线程,为了能清楚地看到线程的运行情况,在主线程创建了子线程之后,
   打印“I'm eatting apples”以确保能够直观的看出运行情况,
   之后调用ExitThread(0)将所有线程撤销。
   ExitThread(0)的使用:
   	void eatApple(int number){
	Sleep((3 - number)*1000);
	printf("I'm eatting #%d apples.\n",number);
		while(1){
			printf("#%d is exiting.\n\n",number);
			ExitThread(0);
		}
	}
PS:视频中用的是这种方法,但是我在学习文档中看到ExitThread(0)表示要撤销进程中的所有线程。所以我没用视频中的方法,直接在代码后面加了“ExitThread(0);”语句。

在这里插入图片描述
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_44919455/article/details/105629695

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签