【操作系统】实验一 线程的创建与撤销

实验一

一、实验目的

(1)熟悉windows系统提供的线程创建与撤销系统调用.

(2)掌握windows系统环境下线程的创建与撤销方法.

二、实验准备

1.创建线程

CreateThread()函数:

在调用进程的地址空间上创建一个线程,执行指定的函数,并返回新建立的线程的句柄。

HANDLE CreateThread(
	LPSECURITY_ATTRIBUTES lpThreadAttributes,    //为线程指定安全属性
	DWORD dwStackSize,  //线程堆栈的大小
	LPVOID lpparameter,  //函数中要传递的参数
	DWORD dwCreationFlags, //指定线程创建后所处的状态
	LPDWORD lpThread  //系统返回的线程标识符
);
2.撤销线程

ExitThread()用于撤销当前进程.

VOID ExitThread(
DWORD dwExitCode);   //dwExitCode:指定线程返回码,可以调用GetExitCodeThread()查询返回码的含义
3.终止线程

TerminateThread()用于终止当前线程.

该函数与ExitThread()的区别在于,ExitThread()在撤销线程时将该线程所拥有的资源全部归还给系统,而TerminateThread()不归还资源.

BOOL TerminateThread(
HANDLE hHandle,       //hThread:要终止线程的线程句柄
DWORD dwExitCode);    //dwExitCode:指定线程返回码,可以调用GetExitCodeThread()查询返回码的含义

函数调用成功,返回一个非0值;若失败,返回0,可调用函数GetLastError()查询失败的原因.

4.挂起线程

Sleep()用于挂起当前正在执行的线程.

VOID Sleep(DWORD dwMilliseconds); //dwMilliseconds:指定挂起时间,单位为ms(毫秒)
5.关闭句柄

函数CloseHandle()用于关闭已打开的对象的句柄,其作用与释放动态申请的内存空间类似,这样可以释放系统资源,使线程安全运行.

BOOL CloseHandle(HANDLE hObject); //hObject:已打开对象的句柄

函数调用成功,返回一个非0值;若失败,返回0,可调用函数GetLastError()查询失败的原因.

6.eatApple()函数:
void eatApple(int apple_number){
	Sleep((3 - apple_number) * 1000);  //休眠时间 (3 - apple_number)s
	printf("I'm eating apple #%d.\n", apple_number);  
}

三、实验内容

(一)实验内容

视频部分:
1.认识工具(实验准备部分)
2.比较两个程序

不使用多线程:按照语句出现的位置顺序执行eatApple()函数

使用多线程:同时执行eatApple()函数,根据休眠时长的顺序从小到大输出

讲义部分:

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

(二)主要代码

视频部分:
// 01.cpp : Defines the entry point for the console application.
//

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

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

/
// The one and only application object

CWinApp theApp;

using namespace std;

void eatApple(int apple_number){
	Sleep((3 - apple_number) * 1000);
	printf("I'm eating apple #%d.\n", apple_number);
	while(1) {
		printf("#%d id is exiting.\n\n",apple_number);
		ExitThread(0);
	}
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;
	HANDLE handle1 = NULL;
	HANDLE handle2 = NULL;
	HANDLE handle3 = NULL;
	DWORD ThreadID1 = NULL;
	DWORD ThreadID2 = NULL;
	DWORD ThreadID3 = NULL;
	int a=0;
	int b=1;
	int c=2;

	handle1=CreateThread((LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) eatApple,
		(LPVOID)a,
		0,
		&ThreadID1);

	handle2=CreateThread((LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) eatApple,
		(LPVOID)b,
		0,
		&ThreadID2);

	handle3=CreateThread((LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) eatApple,
		(LPVOID)c,
		0,
		&ThreadID3);

	Sleep(10000);
	return nRetCode;
}

讲义部分:
// ThreadName1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "ThreadName1.h"

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

/
// The one and only application object

CWinApp theApp;

using namespace std;

void ThreadName()
{
	printf("Thread is Running!\n");
}
static HANDLE hHandle1=NULL; 
DWORD ThreadID1;
  
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;
	HANDLE hHandle = NULL;
	DWORD ThreadID = NULL;
    
	hHandle=CreateThread((LPSECURITY_ATTRIBUTES) NULL,
		0,
		(LPTHREAD_START_ROUTINE) ThreadName,
		(LPVOID)NULL,
		0,
		&ThreadID);
	Sleep(5000);
	CloseHandle(hHandle);
	ExitThread(0);
	
	return nRetCode;

}

四、实验结果与总结

视频部分:

结果:

1.不使用多线程时的输出顺序:0、1、2

2.多线程输出顺序:2、1、0
在这里插入图片描述

ExitThread(0)函数在退出线程后即可退出while(1){}死循环。

注意:使用多线程实验时Sleep(10000);语句不能省略,否则会出现主线程结束将子线程也结束的情况。

总结:

1.通过两个程序的执行非常直观的感受使用多线程的区别。

2.多线程同时执行eatApple()函数,并由休眠时长的不同决定输出顺序

3.线程是操作系统中能够进行运算调度的最小单位。

4.多线程使用非常广泛,充分利用网络带宽,提高了程序的效率。

讲义部分:

结果:

image

总结:
  • 通过CreateThread()函数创建子线程

    (CreateThread()函数中指明了线程要执行的ThreadName()函数)

  • 调用Sleep(5000)函数挂起线程5s**(这里注意sleep()函数参数的单位为ms)**

  • 使用ExitThread(0)撤销进程

遇到的问题与解决方法:

①安装后运行初始程序时发现无法运行,在网上搜索后发现是VC++ 安装在了C盘中的原因。在打开vc++时 右击→以管理员身份运行,即可解决。

②运行程序时报错:关于fatal error C1083: Cannot open precompiled header file: /‘Debug/v13_3.pch/’: 错

百度后得知这个错误是预编译文件的设置造成的,单独编译StdAfx.cpp 即可解决。

③一开始没有发现ThreadName()函数被调用,后来在CreateThread()函数的参数中发现LPSECURITY_START_ROUTINE lpStartAddress 指定了线程要执行的函数,由此,在线程被创建时输出Thread is Running!

///

  • 7
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值