操作系统实验 实验二:线程的同步

实验二:线程的同步

2.2.1 实验目的

​ 进一步掌握windows系统环境下线程的创建和撤销

​ 熟悉windows系统提供的线程同步API(是WINDOWS提供给应用程序与操作系统的接口)

​ 使用windows系统提供的线程同步API解决实际问题

2.2.2 实验准备知识:相关API函数介绍

2.2.2.1等待对象 (一个)

​ 等待对象(wait fuctions)函数包括等待一个对象 (WaitForSingleObject())和等待多对象 (WaitForMultipleObject())两个API函数。等待一个对象WaitForMultipleObject()用于等 待一个对象。他等待的对象可以为以下对象之一。

​ Change notification:变化通知。

​ Console input:控制台输入。

​ Events:事件。

​ Job:作业。

​ Mutex:互斥信号量。

​ Process:进程。

​ Semaphore:计数信号量。

​ Thread:线程。

​ Waitable timer:定时器。

​ 原型:

​ DWORD WaitForSingleObject(

​ HANDLE hHandle, //对象句柄

​ DWORD dwMilliseconds //等待时间

​ );

​ 参数说明:

​ hHandle:等待对象的对象句柄。该对象句柄必须为SYNCHRONIZE([ˈsɪŋkrənaɪz],同步)访问。

​ dwMilliseconds:等待时间,单位为ms。若改值为0,函数在测试对象的状态后立即返回,若为 INFINITE(无限的),函数一直等待下去,直到收到一个信号将其唤醒,如表2-1所示。

​ 返回值:

​ 如果返回成功,其返回值说明是何种事件导致函数返回。

函数描述:


访问 描述

WAIT_ABANDONED 等待对象的是一个互斥(mutex)对象,该互斥对象没有被拥有它的线程释放,他被设置为不能被唤醒

WAIT_OBJECT_0 指定对象被唤醒

WAIT_TIMEOUT 超时


​ 用法举例:

​ Staitic HANDLE hHandle1=NULL;

​ DWORD dRes;

​ dRes=WaitForSingleObject(hHandle1, 10); //等待对象的句柄为hHandle,等待时间1000ms

2等待对象 (多个)

​ 等待多个对象WaitForMultipleObject()在指定时间内等待多个对象,他等待的对象与 WaitForSingleObject()相同。

​ 原型:

​ DWORD WaitForMultipleObject(

​ DWORD nCount, //句柄数组中的句柄数

​ XONST HANDLE *lpHandles, //指向对象句柄数组的指针

​ BOOL fWaitAll, //等待类型

​ DWORD dwMilliseconds //等待时间

​ );

​ 参数说明:

​ nCount:由指针*lpHandles指定的句柄数组中的句柄数,最大数是 MAXIMUM_WAIT_OBJECTS。

​ *lpHandles:指向对象句柄数组的指针。

​ fWAitAll:等待类型。若存为true,当由lpHandles数组指定的所有对象被唤醒时函数返 回;若为FALSE,当由lpHandles数组制定的某一个对象被唤醒时函数返回,且有返回值 说明事由哪个对象引起的函数返回。

​ dwMilliseconds :等待时间。单位为ms。若该值为0,函数测试对象的状态后立即返 回;若为INFINITE,函数一直等待下去,直到收到一个信号将其唤醒。

​ 返回值:

​ 如果成功返回,其返回值说明是何种事件导致函数返回。

3 信号量对象

​ 信号量对象(semaphore)包括创建信号量(CreateSemaphore())打开信号量 OpenSemaphore()及增加信号量的值(ReleaseSemaphore())API函数。

​ 创建信号量

​ CreateSemaphore()用于创建一个信号量。

​ 原型:

​ HANDLE CreateSemaphore(

​ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,//安全属性

​ LONG lInitialCount, //信号量对象初始值

​ LONG liMaximumCount, //信号量最大值

​ LPCTSTR lpName //信号量名

​ );

​ 参数说明:

​ lpSemaphoreAttributes:指定安全属性,为null是,信号量得到一个默认的安全描述符。

​ lInitialCount:指定信号量对象的初始值。该值必须大于等于0,小于等于lMaximumCount 。当其值大于0是,信号量被唤醒。当该函数释放了一个等待该信号量的线程时, lInitialCount值减1,当调用函数ReleaseSemaphore()时,按其指定的数量加一个值。

​ lMaximumCount:指出该信号量的最大值,该值必须大于0.

​ lpName:给出该信号量的名字。

​ 返回值:

​ 信号量创建成功,将返回该型号量的句柄。如果给出的信号量名是系统已经存在的信号量, 将返回这个已经存在的信号量的句柄。如果失败,系统返回null,还可以调用函数 GEtLastError()查询失败的原因。

​ 用法举例:

​ Static HANDLE hHandle1=null;

​ //创建一个信号量,其初值为0,最大值为5,信号量的名字为“SemphoreName1”

​ hHnadle1= CreateSemaphore(NULL,0,5,"SemphoreName1");

							 打开信号量

​ OpenSemaphore()用于打开一个信号量。

​ 原型:

​ HANDLE OpenSemaphore(

​ DWORD dwDesidedAccess, //访问标志

​ BOOL bInheritHandle, //继承标志

​ LPCTSTR lpNme //信号量名

​ );

​ 参数说明:

​ (1).dwDesiredAccess:指出打开后要对信号量进行何种访问,如下所示。

​ 访问 描述

​ SEMAPHORE_ALL_ACCESS 可以进行任何对信号量的访问

​ SEMPHORE_MODFIY_STATE 可以使用ReleaseSemaphore()修改信号量的值,使信号量的 值成为可用状态

​ SYNCHRONIZE 使用等待函数(wait functions),等待信号量成为可用状态

​ (2). bInheritHandle:指出返回的的信号量句柄是否可以继承。

​ (3).lpName:给出信号量的名字

​ 返回值:

​ 信号量打开成功,将返回信号量的句柄;如果失败,系统返回null,可以调用函数 GetLastError()查询失败的原因。;

​ 用法举例:

​ Static HANDLE hHandle1=null;

​ //打开一个名为 ” SemphoreName1 ” 的信号量,之后可使用ReleaseSemaphore()函数增加 信号量的值hHandle1=OpenSemaphore(SEMAPHORE_MOFDIFY_START,NULL, ” SemphoreName1” );

3. 增加信号量的值

​ ReleaseSemaphore()用于增加信号量的值。

​ 原型:

​ BOOL ReleaseSemaphore(

​ HANDLE hSemaphore, //信号量对象句柄

​ LONG lReleaseCount, //信号量要增加数值

​ LPLONG lpPreiousCount //信号量要增加数值地址

​ );

​ 参数说明:

​ (1).hSemaphore:创建或打开信号量时给出的信号量对象句柄。Windows NT中建议使用 SEMAPHORE_MODIFY_STARTE访问属性打开该信号量。

​ (2). lReleaseCount:信号量要增加数值。该值必须大于0。如果增加该值后大于信号创建时 给出的lMaximumCount值,则增加操作失效,函数返回FALSE。

​ (3). lpPreiousCount :接收信号量的一个32位的一个变量。若不需要接受该值,可以指定 为null。

​ 返回值:

​ 如果成功,将返回一个非0值;如果失败,系统返回一个0,可以调用一个GetLastError() 查询失败的原因。

​ 用法举例:

​ Static HANDLE hHandle1=NULL;

​ BOOL rc;

​ rc= ReleaseSemaphore(hHandle1,1,NULL);//给信号量的值加1;

2.2.3实验内容

完成主子两个线程之间的同步,要求子线程先执行。在主线程中使用系统调用 CreateThread()创建一个 子线程。主线程创建一个子线程后进入阻塞状态,直到子线程运行完毕后唤醒主线程。

2.2.4实验要求

​ 能正确使用等待对象、WaitForSingleObject()或WaitForMultipleObject(0及信号量对象 CreateSemaphore()、OpenSemaphore()、ReleaseSemaphore()等系统调用,进一步理解线程的同步。

2.2.5实验指导

具体操作过程同本章实验一,在Microsoft visual C++6.0环境下建立一个MFC支持的控制台文件,编写C程序,在程序中使用CreateSemaphore(NULL,0,1,”SemaphoreName1”)创建一个名为“SemaphoreName1”的信号量,信号量的初始值为0,之后使用OpenSemaphore(SYNCHRONIZE|SEMAPHORE_MODIFY_STARTE,NULL, ”SemaphoreName1)打开该信号量,这里访问标志使用“SYNCHRONIZE|SEMAPHORE_MODIFY_STARTE”,以便之后可以使用WaitForSingleObject()等待该信号量及使用ReleaseSemaphore()释放该信号量,然后创建一个子线程,主线程创建子线程后调用WaitForSingleObject(hHandle1,INFINITE),这里等待时间设置为INFINITE表示一直等待下去,直到该信号量被唤醒为止。子线程结束,调用ReleaseSemaphore(hHandle1,1,NULL)释放信号量,使信号量的值加1。

2.2.6实验总结

实验完成了主、子线程的同步,主线程创建子线程后,主线程塞,让子线程先执行,等子线程执行完后,由子线程唤醒子线程。主子线程运行情况如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VWMKTzSc-1586510532837)(C:\Users\先\AppData\Roaming\Typora\typora-user-images\image-20200410170622581.png)]

2.2.7 源程序

// Semaphore.cpp : Defines the entry point for the console application.

//

#include “stdafx.h”

#include " Semaphore.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;

static HANDLE h1; //线程句柄

static HANDLE hHandle1=NULL; //信号量句柄

void func();

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

​ int nRetCode = 0;

​ DWORD dwThreadID1;

​ DWORD dRes,err;

hHandle1=CreateSemaphore(NULL,0,1,“SemaphoreName1”);//创建一个信号量

​ if (hHandle1==NULL)printf(“Semaphore Create!\n”);

​ else printf(“Semaphore Create Success!\n”);

hHandle1=OpenSemaphore(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE,

​ NULL,

​ “SemaphoreName1”); //打开信号量

​ if (hHandle1==NULL) printf(“Semaphore Open Fail!\n”);

​ else printf(“Semaphore Open Success!\n”);

​ h1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,

​ 0,

​ (LPTHREAD_START_ROUTINE)func,

​ (LPVOID)NULL,

​ 0,&dwThreadID1); //创建子线程

​ if (h1==NULL) printf(“Thread1 create Fail!\n”);

else printf(“Thread1 create Success!\n”);

dRes=WaitForSingleObject(hHandle1,INFINITE); //主线程等待子线程结束

err=GetLastError();

printf(“WaitForSingleObject err = %d\n”,err);

​ if (dRes==WAIT_TIMEOUT) printf(“TIMEOUT!dRes=%d\n”,dRes);

else if (dRes==WAIT_OBJECT_0) printf(“WAIT_OBJECT!dRes=%d\n”,dRes);

else if (dRes==WAIT_ABANDONED)

printf(“WAIT_ABANDONED!Dres=%d\n”,dRes);

else printf(“dRes =%d\n”,dRes);

CloseHandle(h1);

CloseHandle(hHandle1);

ExitThread(0);

​ return nRetCode;

}

void func()

{

BOOL rc;

DWORD err;

printf(“Now In Thread!\n”);

rc =ReleaseSemaphore(hHandle1,1,NULL);

err =GetLastError(); //子线程唤醒主线程

printf(“ReleaseSemaphore err=%d\n”,err);

if(rc==0) printf(“Semaphore Release Fail!\n”);

else printf(“Semaphore Release Success!rc= %d\n”,rc);

}

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值