操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】

操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第1张图片

一、实验目的与要求

熟悉Windows系统提供的线程创建与撤销等API系统调用,掌握Windows系统环境下线程的创建与撤销方法、掌握线程实现同步和互斥的实现原理和方法,了解在windows环境下是如何进行线程调度的。操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第2张图片


二、实验内容

1、熟悉开发环境Visual C++ 6.0;
2、Windows系统环境下线程的创建与撤销方法;
3、编程:在主线程中调用CreateThread( )创建子线程,并在子线程中显示类似“Thread is running !”等字样。
4、线程互斥的实现
5、线程同步的实现


三、背景知识

1、CreateThread函数
功能: 在调用进程的虚拟空间中创建一个线程。 函数原型:HANDLE WINAPI
CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T
dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID
lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId)

参数描述:
lpThreadAttributes: 输入参数,可选。指向SECURITY_ATTRIBUTES类型的结构体指针,决定返回的线程句柄是否可以被子线程继承。如果该参数为NULL则使用默认安全性,不可以被子线程继承;否则需要定义一个SECURITY_ATTRIBUTES类型的结构体并将它的bInheritHandle成员初始化为TRUE。
dwStackSize: 输入参数。设置初始堆栈的大小,以字节为单位,如果为0,新线程默认使用与调用该函数的线程相同的栈空间大小。
lpStartAddress: 输入参数,指向线程函数的地址指针。定义线程函数格式如下:
(1)DWORD WINAPI 函数名(LPVOID lpParam)。
(2)如果使用void 函数名(LPVOID lpParam)进行定义,则lpStartAddress必须写成(LPTHREAD_START_ROUTINE)函数名。
lpParameter:输入参数。向线程函数传递参数的指针,不需传递参数时设为NULL。
dwCreationFlags:输入参数。控制线程创建的标志,取值如下:
(1)0:表示线程创建后立即运行。
(2)CREATE_SUSPENDED(0x00000004):创建一个挂起的线程,直到调用ResumeThread函数后开始运行。
(3)STACK_SIZE_PARAM_IS_A_RESERVATION(0x00010000):dwStackSize参数指定初始的保留堆栈的大小,如果没说明该参数,dwStackSize指定提交的大小。
lpThreadId:输出参数。DWORD类型变量的指针,用以保存新线程的id,如不需返回新线程的id则设为NULL。
返回值: 函数成功,返回线程句柄;函数失败返回false。
注意: 线程标识(ThreadId)和线程句柄(Handle)概念不同。线程标识是一个32位无符号整数,其值系统唯一,通常利用线程标识可以进一步获取线程的其它信息,不能控制线程。而线程句柄表面上看也是一个32位无符号整数且系统唯一,但它是一个内核对象的标识,通过它可以控制线程,属于系统资源,用完后一定要用CloseHandle()函数关闭,从而将该资源归还给系统。需要注意的是CloseHandel()只是关闭了一个线程句柄对象,表示不再使用该句柄对线程做任何控制了,并没有结束线程。

2、CreateMutex函数

功能: 创建一个有名或无名的互斥信号量对象。 函数原型:HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
lpMutexAttributes: 参见 CreateThread函数。
bInitialOwner: 输入参数。如创建进程希望立即拥有互斥体,则设为TRUE,否则设定为FALSE。
lpName: 指定互斥体对象的名字。用vbNullString创建一个未命名的互斥体对象。如已经存在拥有这个名字的一个事件,则打开现有的已命名互斥体。这个名字可能不与现有的事件、信号机、可等待计时器或文件映射相同。
例如: h_mutex1=CreateMutex(NULL,FALSE,“mutex_for_readcount”);

3、WaitForSingleObject函数

功能: 当指定对象存在信号量或超时返回。 函数原形:DWORD WaitForSingleObject(HANDLE
hHandle,DWORD dwMilliseconds);
hHandle: 对象句柄。
dwMilliseconds: 定时时间间隔,单位为milliseconds(毫秒)。如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。如果dwMilliseconds为0,即便没有信号量,也会立即从函数返回;如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回。

4、ReleaseMutex函数

功能: 释放互斥对象的控制权。一个线程释放了互斥对象的控制权后,如果其它进(线)程在等待互斥对象置位,则等待的进(线)程可以得到该互斥对象,从等待函数返回,互斥对象被新的进(线)程所拥有。
函数原型: BOOL WINAPI ReleaseMutex(HANDLE hMutex); hMutex:输入参数,制定一个互斥体的句柄。
返回值: TRUE表示成功,FALSE表示失败。

5、CreateSemaphore函数

功能: 创建或打开一个命名或未命名的信号量对象。 函数原形:HANDLE
CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG
lInitialCount,LONG lMaximumCount, LPCTSTRlpName);

参数描述:
lpSemaphoreAttributes: 输入参数,可选。指向SECURITY_ATTRIBUTES类型的结构体指针,决定返回的信号量句柄是否可以被子线程继承(参见创建线程)。
lInitialCount: 输入参数。设置信号量的初始计数,可设置零到lMaximumCount之间的任意一个值。大于0的值表示有信号,0表示无信号。每执行WaitForSingleObject函数一次,计数值就减一;每执行ReleaseSemaphore函数一次,信号量按照该函数说明的数量递增。
lMaximumCount: 输入参数。设置信号量的最大计数值(必须大于0)。
lpName: 输入参数。指定信号量对象的名称,如果该参数为Null则产生未命名的信号量对象;如果该参数非空,且系统中存在同名信号量对象,则该函数请求信号量的SEMAPHORE_ALL_ACCESS权限。
返回值: 如执行成功,返回信号量对象的句柄。零表示出错,会设置GetLastError。即使返回一个有效的句柄,但系统中存在同名的信号量,则GetLastError返回ERROR_ALREADY_EXISTS值。

6、ReleaseSemaphore函数

功能: 用于对指定的信号量增加指定的值。 函数原形:BOOL ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount);

参数描述:
hSemaphore: 输入参数。所要操作的信号量对象的句柄,该句柄是CreateSemaphore或者OpenSemaphore函数的返回值,并且必须有SEMAPHORE_MODIFY_STATE的访问权限。
lReleaseCount: 输入参数。信号量对象在当前基础上所要增加的值,这个值必须大于0。如果信号量的当前值加上lReleaseCount以后导致信号量的值大于信号量的最大值,那么信号量的当前值不变,同时函数返回FALSE。
lpPreviousCount: 输出参数。指向返回信号量上次值的变量的指针,如果不需要信号量上次的值,该参数可以设置为NULL。
返回值: 如果成功返回非0;失败返回0,可以调用GetLastError函数得到详细出错信息。


四、实验原理

1、线程互斥实现原理

打开VC++6.0开发环境,创建一个源文件,在主函数中利用CreateThread函数创建2个线程,创建后立即执行,每个线程执行10次,分别对共享变量R执行加1操作,R的初值为0,使用Sleep函数控制线程的执行速度。为了实现互斥使用R,需在主函数中,利用CreateMutex

创建一个互斥体,在访问R前利用WaitForSingleObject函数测试互斥体信号是否存在,如该信号存在则可以访问R并上锁(排斥其它线程访问R),使用完后利用ReleaseMutex函数释放资源并唤醒等待R资源而阻塞的线程;如该信号不存在,则该线程阻塞。

2、线程同步实现原理

打开VC++6.0开发环境,创建一个源文件,在主函数中利用CreateThread函数创建生产者线程和消费者线程,创建后立即执行,每个线程执行10次。其中生产者线程完成向共享缓冲区送数据,消费者线程负责从共享缓冲区取数据并进行进一步加工处理,缓冲区初始状态为空(生产者线程先执行)。为了正确实现两个线程的同步,需在主函数中利用CreateSemaphore函数创建缓冲区满“full”信号量(初值为0,表示不满)和缓冲区空信号量“empty”(初值为1,表示缓冲区空)。生产者线程送数前利用WaitForSingleObject函数测试empty信号是否存在,如该信号存在则可以往共享缓冲区送数,送完后ReleaseSemaphore函数释放一个full信号;如该信号不存在则说明缓冲区不空,生产者线程应阻塞。而消费者线程在取数前利用WaitForSingleObject函数测试full信号是否存在,如该信号存在则可以从共享缓冲区送数,取完后ReleaseSemaphore函数释放一个empty信号;如该信号不存在则说明缓冲区不满,消费者线程应阻塞。使用Sleep函数控制两个线程的执行速度。


五、程序代码

1.1、线程互斥源代码

#include  
#include   
static int count=0; //共享变量
static HANDLE h1,h2;  //两个子线程的句柄变量
HANDLE g_hMutex;     //互斥信号量句柄,用于诸线程互斥访问缓冲区
using namespace std;
//子线程fun c2的实现
void func2()   
{
	int i,r2;
	for(i=0;i<10;i++)
	{
		Sleep(10);
		WaitForSingleObject(g_hMutex,INFINITE);//此处补齐代码;
		r2=count;    
		r2=r2+1;
		count=r2;
		cout<<"count in func2="<<count<<endl;
		ReleaseMutex(g_hMutex);//此处补齐代码;
	}
}    
//子线程func1的实现,使用互斥信号时,将Sleep语句移到前面
void func1()   
{       
	int r1,i;
	for(i=0; i<10; i++)
	{
		Sleep(30);
		WaitForSingleObject(g_hMutex,INFINITE);//此处补齐代码; 
		r1=count;
		r1=r1+1;
		count=r1;    
		cout<<"count in func1="<<count<<endl;
		ReleaseMutex(g_hMutex);//此处补齐代码; 
	} 
}
//主线程的实现
int main()
{ 
	DWORD  dwThreadID1, dwThreadID2;
	g_hMutex = CreateMutex(NULL,FALSE,"mutex-for-readcount");//此处补齐代码; //创建互斥信号量
	//创建子线程 func1
	h1=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func1,NULL,0,&dwThreadID1);//此处补齐代码;
	cout<<"**********************"<<endl;
	cout<<"********23夏旭********"<<endl;  
	cout<<"**********************"<<endl; 
	if(h1==NULL) cout<<"Thread1 create Fail!"<<endl;
	else cout<<"Thread1 create success!"<<endl;
	//创建子线程 func2
	h2=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func2,NULL,0,&dwThreadID2);//此处补齐代码;       
	if(h1==NULL) cout<<"Thread2 create Fail!"<<endl;
	else cout<<"Thread2 create success!"<<endl;
	Sleep(2000);
	CloseHandle(h1);
	CloseHandle(h2);
	CloseHandle(g_hMutex);
	ExitThread(0);    
}

1.2、线程互斥变式1源代码

#include  
#include   
static int count=0; //共享变量
static HANDLE h1,h2;  //两个子线程的句柄变量
HANDLE g_hMutex;     //互斥信号量句柄,用于诸线程互斥访问缓冲区
using namespace std;
// 变式 1.0 
void func2()   
{
	int i,r2;
	for(i=0;i<10;i++)
	{
		r2=count;    
		r2=r2+1;
		Sleep(13);
		count=r2;
		cout<<"count in func2="<<count<<endl;
	}
}    
void func1()   
{       
	int r1,i;
	for(i=0;i<10;i++)
	{
		r1=count;
		r1=r1+1;
		Sleep(33);
		count=r1;    
		cout<<"count in func1="<<count<<endl;
	} 
}
//主线程的实现
int main()
{ 
	DWORD  dwThreadID1, dwThreadID2;
	g_hMutex = CreateMutex(NULL,FALSE,"mutex-for-readcount");//此处补齐代码; //创建互斥信号量
	//创建子线程 func1
	h1=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func1,NULL,0,&dwThreadID1);//此处补齐代码;
	cout<<"**********************"<<endl;
	cout<<"********23夏旭********"<<endl;  
	cout<<"**********************"<<endl; 
	if(h1==NULL) cout<<"Thread1 create Fail!"<<endl;
	else cout<<"Thread1 create success!"<<endl;
	//创建子线程 func2
	h2=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func2,NULL,0,&dwThreadID2);//此处补齐代码;       
	if(h1==NULL) cout<<"Thread2 create Fail!"<<endl;
	else cout<<"Thread2 create success!"<<endl;
	Sleep(2000);
	CloseHandle(h1);
	CloseHandle(h2);
	CloseHandle(g_hMutex);
	ExitThread(0);    
}

1.3、线程互斥变式2源代码

#include  
#include   
static int count=0; //共享变量
static HANDLE h1,h2;  //两个子线程的句柄变量
HANDLE g_hMutex;     //互斥信号量句柄,用于诸线程互斥访问缓冲区
using namespace std;
//变式2.0 
void func2()   
{
	int i,r2;
	for(i=0;i<10;i++)
	{
		r2=count;    
		r2=r2+1;
		Sleep(3);
		count=r2;
		WaitForSingleObject(g_hMutex,INFINITE);
		cout<<"count in func2="<<count<<endl;
		ReleaseMutex(g_hMutex);
	}
}    
void func1()   
{       
	int r1,i;
	for(i=0;i<10;i++)
	{
		r1=count;
		r1=r1+1;
		Sleep(1);
		count=r1; 
		WaitForSingleObject(g_hMutex,INFINITE);
		cout<<"count in func1="<<count<<endl;
		ReleaseMutex(g_hMutex); //退出临界区
	} 
}
//主线程的实现
int main()
{ 
	DWORD  dwThreadID1, dwThreadID2;
	g_hMutex = CreateMutex(NULL,FALSE,"mutex-for-readcount");//此处补齐代码; //创建互斥信号量
	//创建子线程 func1
	h1=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func1,NULL,0,&dwThreadID1);//此处补齐代码;
	cout<<"**********************"<<endl;
	cout<<"********23夏旭********"<<endl;  
	cout<<"**********************"<<endl; 
	if(h1==NULL) cout<<"Thread1 create Fail!"<<endl;
	else cout<<"Thread1 create success!"<<endl;
	//创建子线程 func2
	h2=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func2,NULL,0,&dwThreadID2);//此处补齐代码;       
	if(h1==NULL) cout<<"Thread2 create Fail!"<<endl;
	else cout<<"Thread2 create success!"<<endl;
	Sleep(2000);
	CloseHandle(h1);
	CloseHandle(h2);
	CloseHandle(g_hMutex);
	ExitThread(0);    
}

2.1、线程同步源代码

#include  
#include 
using namespace std;
HANDLE hThread1; //子线程1的句柄
HANDLE hThread2;//子线程2的句柄
HANDLE hHandle=NULL; //主线程子线程通信信号量
HANDLE hHandle1=NULL; //信号量1的句柄,全局变量 
HANDLE hHandle2=NULL; //信号量2的句柄,全局变量     
DWORD WINAPI producer(LPVOID lpParam)  //生产者线程 
{   
	int i;
	for(i=0;i<10;i++)
	{
		WaitForSingleObject(hHandle2,INFINITE);//此处补齐代码;
		Sleep(10);
        cout<<"生产者线程在运行!"<<endl;
		ReleaseSemaphore(hHandle1,1,NULL);//此处补齐代码;
	}
	return 0;
}
DWORD WINAPI consumer(LPVOID lpParam)  //消费者线程
{   
	int i;
	for(i=0;i<10;i++)
	{
		WaitForSingleObject(hHandle1,INFINITE);//此处补齐代码;
		Sleep(10);
        cout<<"消费者线程在运行!"<<endl;
		ReleaseSemaphore(hHandle2,1,NULL);//此处补齐代码;
	}
	ReleaseSemaphore(hHandle,1,NULL);//此处补齐代码;  //唤醒主线程
	return 0;
}
int main()
{  
    DWORD dwThreadID1,dwThreadID2;
    hHandle=CreateSemaphore(NULL,0,10,NULL);//此处补齐代码; //Semaphore,初值为0
    cout<<"****************************"<<endl;
	cout<<"***********23夏旭***********"<<endl;  
	cout<<"****************************"<<endl; 
    hHandle1=CreateSemaphore(NULL,0,10,NULL);//此处补齐代码; //创建full信号量,初值为0
    if(hHandle1==NULL)  cout<<"full Semaphore Create Fail!"<<endl;
    else  cout<<"full Semaphore Create Success!"<<endl;
    hHandle2=CreateSemaphore(NULL,1,10,NULL);//此处补齐代码; //创建empty信号量,初值为1
    if(hHandle2==NULL)  cout<<"empyt Semaphore Create Fail!"<<endl;
    else  cout<<"empyt Semaphore Create Success!"<<endl; 
    hThread1=CreateThread(NULL,0,producer,NULL,0,NULL);//此处补齐代码;    //创建子线程1
    if(hThread1==NULL)  cout<<"producer create Fail!"<<endl; 
    else  cout<<"producer create Success!"<<endl; 
    hThread2=CreateThread(NULL,0,consumer,NULL,0,NULL);//此处补齐代码;    //创建子线程2
    if(hThread1==NULL)	cout<<"consumer create Fail!"<<endl; 
    else  cout<<"consumer create Success!"<<endl; 
    WaitForSingleObject(hHandle,INFINITE);//此处补齐代码; //主线程等待子线程结束
    cout<<"主函数运行!"<<endl;
    //以下关闭函数 
    CloseHandle(hHandle);
    CloseHandle(hHandle1);
    CloseHandle(hHandle2);
    CloseHandle(hThread1);
    CloseHandle(hThread2);     
    return 0;   
}

2.2、线程同步变式1源代码

#include  
#include 
using namespace std;
HANDLE hThread1; //子线程1的句柄
HANDLE hThread2;//子线程2的句柄
HANDLE hHandle=NULL; //主线程子线程通信信号量
HANDLE hHandle1=NULL; //信号量1的句柄,全局变量 
HANDLE hHandle2=NULL; //信号量2的句柄,全局变量     
DWORD WINAPI producer(LPVOID lpParam)  //生产者线程 
{   
	int i;
	for(i=0;i<10;i++)
	{
		WaitForSingleObject(hHandle2,INFINITE);//此处补齐代码;
		Sleep(10);
        cout<<"生产者线程在运行!"<<endl;
		ReleaseSemaphore(hHandle1,1,NULL);//此处补齐代码;
	}
	return 0;
}
DWORD WINAPI consumer(LPVOID lpParam)  //消费者线程
{   
	int i;
	for(i=0;i<10;i++)
	{
		WaitForSingleObject(hHandle1,INFINITE);//此处补齐代码;
		Sleep(10);
        cout<<"消费者线程在运行!"<<endl;
		ReleaseSemaphore(hHandle2,1,NULL);//此处补齐代码;
	}
	ReleaseSemaphore(hHandle,1,NULL);//此处补齐代码;  //唤醒主线程
	return 0;
}
int main()
{  
    DWORD dwThreadID1, dwThreadID2;
	hHandle=CreateSemaphore(NULL,0,1,NULL);//此处补齐代码; //Semaphore,初值为0

	hHandle1=CreateSemaphore(NULL,1,1,NULL);//此处补齐代码; //创建full信号量,初值为0
    cout<<"****************************"<<endl;
	cout<<"***********23夏旭***********"<<endl;  
	cout<<"****************************"<<endl; 
	if(hHandle1==NULL)  
		cout<<"full Semaphore Create Fail!"<<endl;
	else 
		cout<<"full Semaphore Create Success!"<<endl;
	hHandle2=CreateSemaphore(NULL,0,1,NULL);//此处补齐代码; //创建empty信号量,初值为1
	if(hHandle2==NULL)  
		cout<<"empyt Semaphore Create Fail!"<<endl;
	else 
		cout<<"empyt Semaphore Create Success!"<<endl; 
	hThread1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE)producer, (LPVOID)NULL,0,&dwThreadID1);//此处补齐代码;    //创建子线程1
	if(hThread1==NULL)
		cout<<"producer create Fail!"<<endl; 
	else 
		cout<<"producer create Success!"<<endl; 
	hThread2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE)consumer, (LPVOID)NULL,0,&dwThreadID2);//此处补齐代码;    //创建子线程2
	if(hThread1==NULL)
		cout<<"consumer create Fail!"<<endl; 
	else 
		cout<<"consumer create Success!"<<endl; 
	WaitForSingleObject(hHandle,INFINITE);//此处补齐代码; //主线程等待子线程结束
	cout<<"主函数运行!"<<endl;
	//以下关闭函数 
	CloseHandle(hHandle);
	CloseHandle(hHandle1);
	CloseHandle(hHandle2);
	CloseHandle(hThread1);
	CloseHandle(hThread2);    
	return 0;   
}

2.3、线程同步变式2源代码

#include  
#include 
using namespace std;
HANDLE hThread1; //子线程1的句柄
HANDLE hThread2;//子线程2的句柄
HANDLE hHandle=NULL; //主线程子线程通信信号量
HANDLE hHandle1=NULL; //信号量1的句柄,全局变量 
HANDLE hHandle2=NULL; //信号量2的句柄,全局变量     
DWORD WINAPI producer(LPVOID lpParam)  //生产者线程 
{   
	int i;
	for(i=0;i<10;i++)
	{
		WaitForSingleObject(hHandle2,INFINITE);//此处补齐代码;
		Sleep(10);
        cout<<"生产者线程在运行!"<<endl;
		ReleaseSemaphore(hHandle1,1,NULL);//此处补齐代码;
	}
	ReleaseSemaphore(hHandle,1,NULL);
	return 0;
}
DWORD WINAPI consumer(LPVOID lpParam)  //消费者线程
{   
	int i;
	for(i=0;i<10;i++)
	{
		WaitForSingleObject(hHandle1,INFINITE);//此处补齐代码;
		Sleep(20);
        cout<<"消费者线程在运行!"<<endl;
		ReleaseSemaphore(hHandle2,1,NULL);//此处补齐代码;
	}
	//此处补齐代码;  //唤醒主线程
	return 0;
}
int main()
{  
	DWORD dwThreadID1, dwThreadID2;
	hHandle=CreateSemaphore(NULL,0,1,NULL);//此处补齐代码; //Semaphore,初值为0
	hHandle1=CreateSemaphore(NULL,0,5,NULL);//此处补齐代码; //创建full信号量,初值为0
    cout<<"****************************"<<endl;
	cout<<"***********23夏旭***********"<<endl;  
	cout<<"****************************"<<endl; 
	if(hHandle1==NULL)  
		cout<<"full Semaphore Create Fail!"<<endl;
	else 
		cout<<"full Semaphore Create Success!"<<endl;
	hHandle2=CreateSemaphore(NULL,5,5,NULL);//此处补齐代码; //创建empty信号量,初值为1
	if(hHandle2==NULL)  
		cout<<"empyt Semaphore Create Fail!"<<endl;
	else 
		cout<<"empyt Semaphore Create Success!"<<endl; 
	hThread1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE)producer, (LPVOID)NULL,0,&dwThreadID1);//此处补齐代码;    //创建子线程1
	if(hThread1==NULL)
		cout<<"producer create Fail!"<<endl; 
	else 
		cout<<"producer create Success!"<<endl; 
	hThread2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,(LPTHREAD_START_ROUTINE)consumer, (LPVOID)NULL,0,&dwThreadID2);//此处补齐代码;    //创建子线程2
	if(hThread1==NULL)
		cout<<"consumer create Fail!"<<endl; 
	else 
		cout<<"consumer create Success!"<<endl; 
	WaitForSingleObject(hHandle,INFINITE);//此处补齐代码; //主线程等待子线程结束
	cout<<"主函数运行!"<<endl;
	//以下关闭函数 
	CloseHandle(hHandle);
	CloseHandle(hHandle1);
	CloseHandle(hHandle2);
	CloseHandle(hThread1);
	CloseHandle(hThread2);    
	return 0;   
}

六、结果分析

1.1线程互斥----运行结果图与结果分析

操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第3张图片

创建两个子线程实现进程的互斥,分别对两个子线程给与10次访问共享变量的次数,每次对count+1,当互斥实现时,那么count的最终值为20两个线程分别对count修改10次。那么互斥的实现关键在于互斥体(互斥信号量)的创建,两个子线程在访问count是都要通过WaitForSingleObject函数来确认互斥信号是否存在,如果存在才可以对count进行操作同时排斥其他线程访问R,当次线程的操作结束后释放互斥信号(ReleaseSemaphore函数),那么这时候才允许别的线程访问count。


1.2线程互斥变式1----运行结果图与结果分析

操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第4张图片

变式1在func( )函数中没有wait原语和signal原语,此时count不在是一个共享变量,它可以同时被线程1和线程2进行修改,那么此时线程1和线程2在修改count是获得的count的值就会受到间隔时间的影响,线程1间隔为29毫秒线程2间隔为12毫秒,我们可以看上图中正好出现一个我们需要的数值,那就是线程二在执行第十次的时候返回值为5,真是因为当线程一执行完将count修改为4的时候线程2获得了count为4的值再进行修改就变为5,所以此时两个线程并不互斥的使用变量count。

即:在还没有实现一个语句的完整输出时,就被sleep( )函数打断,开始输出另一个语句了,在输出完另一个语句以后,继续输出之前被打断并未完整输出的。这是因为显示器是一个独占资源,在实现过程中要互斥,而程序既没有对屏幕互斥,也没有对count进行互斥,2个线程交织了。


1.3线程互斥变式2----运行结果图与结果分析

操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第5张图片
这个跟第二个相似,count不互斥,输出结果互斥,也就是“输出都是完整的,但是count的值是错误的”。它把WaitForSingleObject函数和ReleaseSemaphore函数之间只放了输出,所以输出互斥结果不互斥。除此之外,改变sleep( )函数中的值的时候,输出会发生改变。


2.1线程同步----运行结果图与结果分析

操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第6张图片
在生产者线程函数DWORD WINAPI producer(LPVOID lpParam)和消费者线程函数DWORD WINAPI consumer(LPVOID lpParam)中,主语句放在wait原语和signal原语之间,这是正确的做法。在创建缓冲区时的初始值为0,最大为1,所以同步实现时是生产者与消费者交替10次并且生产者先行。hHandle1和hHandle2两个信号量分别代表full和empty信号量,但我们需要给hHandle1一个信号量,保证首先运行生产者线程在运行!之后创建两个线程hThread1和hThread2,让两线程同步执行。之后便会出现上图打印情况。最终在打印结束后会唤醒主线程,结束程序。


2.2线程同步变式1----运行结果图与结果分析

操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第7张图片
初步修改之后,消费者进程能够在生产者进程之前实现了,但是在结束之前,第10个生产者进程没有来得及实现,这时,只要把原语移动一下位置就可以实现了。当前的生产者进程执行次数为10次,如不是我们可以让hHandle1信号量为1并且每次hHandle1、hHandle2的信号量增1就可以了,在消费者消费了hHandle1的1之后就会去hHandle2自加1,之后hHandle2自加1就会形成,先执行消费者,再执行生产者,一直持续10次。


2.3线程同步变式2-----运行结果图与结果分析

操作系统之进程管理——生产者&消费者实现线程同步&互斥【详细代码&原理解析】_第8张图片
这里设置了5个缓冲区且初始设置为空并且改变了2个进程的速度当生产者将缓冲区填满后消费者才开始取出,又因为生产者速度快所以后面交替进行,当生产者结束后消费者才连续执行。也就是先让hHandle1为0,从而让生产者先执行,在生产者执行完毕后让hHandle1自增4(只要不是1就行),这样,消费者可以多执行几次


你可能感兴趣的:(#,操作系统,多线程,操作系统,linux)