天天看点

win32线程创建、线程同步以及读者写者问题

include "stdafx.h" 
#include <stdio.h>  
#include <windows.h>  
#include <process.h>

//设置控制台输出颜色  
BOOL SetConsoleColor(WORD wAttributes)  
{  
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);  
	if (hConsole == INVALID_HANDLE_VALUE)  
		return FALSE;  

	return SetConsoleTextAttribute(hConsole, wAttributes);  
}

//设置控制台输出蓝色字体
void ConsolePrintBlue(char *pszFormat, ...)  
{  
	va_list   pArgList;  
	va_start(pArgList, pszFormat);  
	SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN);
	vfprintf(stdout, pszFormat, pArgList); 
	SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 
	va_end(pArgList);  
}

//线程函数
unsigned int __stdcall Threadfun(LPVOID lpParam)  
{  
	LPDWORD pData = (LPDWORD)lpParam;

	for(int i = 0;i < 10; i++)  
	{  
		Sleep(100);  //子线程挂起100毫秒
		printf("Thread_ID = %d , \tParameters = %d, \ti = %d\n", GetCurrentThreadId(), *pData, i);  
	}  
	_endthreadex(0);  
	return 0;  
}  

//如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()
void ThreadexTest()
{
	ConsolePrintBlue("--------- 进入线程创建、挂起、关闭测试 ---------\n");
	DWORD Para0, Para1;  // 设置线程传递参数
	HANDLE hThread[2];  
	Para0 = 0; Para1 = 1;   
	
	//创建线程0并挂起
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, Threadfun, &Para0, CREATE_SUSPENDED, NULL);  
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, Threadfun, &Para1, 0, NULL);  
	
	Sleep(110);  //主线程挂起110毫秒,期间线程1正好可以输出一次
	ResumeThread(hThread[0]);    //恢复线程0
	SuspendThread(hThread[1]);   //挂起线程1
	Sleep(510); //主线程挂起510毫秒,期间线程0正好可以输出5次

	//终止线程0的运行
	TerminateThread(hThread[0], 0);  //并不保证线程被终止,最好采用线程函数返回方式终止
	ResumeThread(hThread[1]);        //恢复线程1
	WaitForSingleObject(hThread[1], INFINITE);   //等待线程1执行完
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);

	ConsolePrintBlue("--------- 结束线程创建、挂起、关闭测试 ---------\n\n\n");
}

CRITICAL_SECTION g_cs;
//关键段线程函数
unsigned int _stdcall  CriticalSection(LPVOID lpParam)
{ 
	EnterCriticalSection(&g_cs);//进入关键段
	printf("Thread_ID%d start\n", GetCurrentThreadId());
	ConsolePrintBlue("挂起线程100毫秒\n");
	Sleep(100);  //挂起线程100毫秒
	printf("Thread_ID%d end\n\n", GetCurrentThreadId());
	LeaveCriticalSection(&g_cs);//离开关键段
	_endthreadex(0);
	return 0;
}

//关键段测试函数
void CriticalSectionTest()
{
	ConsolePrintBlue("\n--------- 使用临界区(CRITICAL_SECTION及其系列函数)实现线程同步 ---------\n");
	InitializeCriticalSection(&g_cs);    //初始化g_cs的成员 
	
	HANDLE hThread[10]; 
	for(int i = 0; i < 10; i++)
	{ 
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, CriticalSection, NULL, 0, NULL);  
	}

	WaitForMultipleObjects(10, hThread, TRUE, INFINITE);   
	for(int i = 0; i < 10; i++)
	{
		CloseHandle(hThread[i]);
	} 
	DeleteCriticalSection(&g_cs);//删除关键段

	ConsolePrintBlue("\\----- end ------\n\n\n");
}


RTL_SRWLOCK  lock;
//互斥锁线程函数
unsigned int _stdcall  SrwLock(LPVOID lpParam)
{ 
	AcquireSRWLockExclusive(&lock);  //进入读写锁
	printf("Thread_ID%d start\n", GetCurrentThreadId());
	ConsolePrintBlue("挂起线程100毫秒\n");
	Sleep(100);  //挂起线程100毫秒
	printf("Thread_ID%d end\n\n", GetCurrentThreadId());
	ReleaseSRWLockExclusive(&lock);  //结束读写锁
	_endthreadex(0);
	return 0;
}

//互斥锁测试函数
void SrwLockTest()
{
	ConsolePrintBlue("\n--------- 使用互斥锁(RTL_SRWLOCK及其系列函数)实现线程同步 ---------\n");
	HANDLE hThread[10]; 
	InitializeSRWLock(&lock);//初始化lock的成员 
	for(int i = 0; i < 10; i++)
	{ 
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, SrwLock, NULL, 0, NULL);  
	}

	WaitForMultipleObjects(10, hThread, TRUE, INFINITE);   
	ConsolePrintBlue("\\----- end ------\n\n\n");
}


HANDLE semaphore;
//信号量线程函数
unsigned int _stdcall  Semaphore(LPVOID lpParam)
{
	WaitForSingleObject(semaphore, INFINITE);  //执行WaitForSingleObject一次,计数值就减一 
	printf("Thread_ID%d start\n", GetCurrentThreadId());
	ConsolePrintBlue("挂起线程100毫秒\n");
	Sleep(100);
	printf("Thread_ID%d end\n\n", GetCurrentThreadId());
	ReleaseSemaphore(semaphore, 1, NULL);    //计数加一
	_endthreadex(0);
	return 0;
}

//信号量测试函数
void SemaphoreTest()
{
	ConsolePrintBlue("\n--------- 使用信号量内核对象实现线程同步 ---------\n");
	HANDLE hThread[10];
	semaphore = CreateSemaphore(NULL, 1, 1, NULL);  //初始计数为1,最大计数为1
	
	for(int i = 0; i < 10; i++)
	{ 
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, Semaphore, NULL, 0, NULL);  
	}

	WaitForMultipleObjects(10, hThread, TRUE, INFINITE);   
	CloseHandle(semaphore);
	ConsolePrintBlue("\\----- end ------\n\n\n");
}

HANDLE hEvent; 
//事件线程函数
unsigned int _stdcall  Event(LPVOID lpParam)
{
	WaitForSingleObject(hEvent, INFINITE);  //自动复位,变为无信号
	printf("Thread_ID%d start\n", GetCurrentThreadId());
	ConsolePrintBlue("挂起线程100毫秒\n");
	Sleep(100);
	printf("Thread_ID%d end\n\n", GetCurrentThreadId());
	SetEvent(hEvent);    //设置为有信号
	_endthreadex(0);
	return 1;
}

//事件测试函数
void EventTest()
{
	ConsolePrintBlue("\n--------- 使用事件内核对象实现线程同步 ---------\n");
	HANDLE hThread[10];
	hEvent = CreateEvent(NULL, false, true, NULL); //初始bManualReset设置为false,bInitialState设置为有信号

	for(int i = 0; i < 10;i++)
	{
		hThread[i] =(HANDLE)_beginthreadex(NULL, 0, Event , NULL, 0, NULL);  
	}
	WaitForMultipleObjects(10, hThread, TRUE, INFINITE);   
	CloseHandle(hEvent);

	ConsolePrintBlue("\\----- end ------\n\n\n");
}


const int QUEUE_LEN = 10;  //环形队列长度
int g_queue[QUEUE_LEN];    //环形队列
int g_i, g_j;                
int nDataR, nDataW;       
HANDLE g_hEmpty, g_hFull;    //读写信号量,读者在读信号量不为空则可读,写者在写信息量不为满则可写 
HANDLE g_hEventReader, g_hEventWriter;  //读者、写者事件,仅能一次一个写者进行写操作,一个读者进行读操作

//读者线程输出函数
void ReaderPrintRed(char *pszFormat, ...)  
{  
	va_list   pArgList;  
	va_start(pArgList, pszFormat);  
	EnterCriticalSection(&g_cs);  
	SetConsoleColor(FOREGROUND_RED);
	vfprintf(stdout, pszFormat, pArgList); 
	SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 
	LeaveCriticalSection(&g_cs);  
	va_end(pArgList);  
}  

//写者线程输出函数  
void WriterPrintGreen(char *pszStr, ...)  
{  
	va_list pArgList;  
	va_start(pArgList, pszStr); 
	EnterCriticalSection(&g_cs);  
	SetConsoleColor(FOREGROUND_GREEN);   
	vfprintf(stdout, pszStr, pArgList); 
	SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
	LeaveCriticalSection(&g_cs);  
}   

//单个读者线程函数
unsigned int __stdcall ReaderThreadFun(PVOID pM)  
{  
	ReaderPrintRed("编号为%d的读者开始读取数据...\n", GetCurrentThreadId());  
	
	int nDataR = 0;  
	while (nDataR < 20)  
	{  
		WaitForSingleObject(g_hFull, INFINITE);  //等待数据队列不为空 
		nDataR = g_queue[g_i];  
		g_i = (g_i + 1)%QUEUE_LEN;  
		ReaderPrintRed("编号为%d读者从队列中读取数据%d\n", GetCurrentThreadId(), nDataR);  
		ReleaseSemaphore(g_hEmpty, 1, NULL);  
	} 

	ReaderPrintRed("编号为%d的读者结束读取数据//end\n", GetCurrentThreadId());  
	return 0;  
}

//单个写者线程函数
unsigned int __stdcall WriterThreadFun(PVOID pM)  
{  
	WriterPrintGreen("编号为%d的写者开始写数据...\n", GetCurrentThreadId());
	
	int nDataR = 0;  
	while (nDataR < 20)  
	{  
		WaitForSingleObject(g_hEmpty, INFINITE);   //等待数据队列有空位
		g_queue[g_j] = ++nDataR;  
		g_j = (g_j + 1)%QUEUE_LEN;  
		WriterPrintGreen("编号为%d写者将数据%d写入队列\n", GetCurrentThreadId(), nDataR); 
		ReleaseSemaphore(g_hFull, 1, NULL);       //g_hFull信号量加一
	} 

	WriterPrintGreen("编号为%d的写者结束写数据//end\n", GetCurrentThreadId());  
	return 0;  
} 

//多个读者线程函数
unsigned int __stdcall MultiReaderThreadFun(PVOID pM)
{
	ReaderPrintRed("编号为%d的读者开始读取数据...\n", GetCurrentThreadId());  
	while (nDataR < 20)  
	{  
		WaitForSingleObject(g_hEventReader, INFINITE);  //一次只能进入一个读者

		if (nDataR >= 20)  
		{
			SetEvent(g_hEventReader);
			ReaderPrintRed("编号为%d的读者结束读数据..//end\n", GetCurrentThreadId());  
			return 0;
		}
		
		WaitForSingleObject(g_hFull, INFINITE);
		nDataR = g_queue[g_i];  
		g_i = (g_i + 1)%QUEUE_LEN;  
		ReaderPrintRed("编号为%d读者从队列中读取数据%d\n", GetCurrentThreadId(), nDataR);
		ReleaseSemaphore(g_hEmpty, 1, NULL);

		SetEvent(g_hEventReader);
	
	}  
	ReaderPrintRed("编号为%d的读者结束读取数据//end\n", GetCurrentThreadId());  
	return 0;  
}

//多个写者线程函数
unsigned int __stdcall MultiWriterThreadFun(PVOID pM)
{   
	WriterPrintGreen("编号为%d的写者开始写数据...\n", GetCurrentThreadId());
	
	while (nDataW < 20)  
	{  
		WaitForSingleObject(g_hEventWriter, INFINITE);  //一次仅能进入一个读者

		if (nDataW >= 20)
		{
			SetEvent(g_hEventWriter);
			WriterPrintGreen("编号为%d的写者结束写数据..//end\n", GetCurrentThreadId());  
			return 0;
		}
		
		WaitForSingleObject(g_hEmpty, INFINITE);
		g_queue[g_j] = ++nDataW;  
		g_j = (g_j + 1) % QUEUE_LEN;  
		WriterPrintGreen("编号为%d的写者将数据%d写入队列\n", GetCurrentThreadId(), nDataW);  
		ReleaseSemaphore(g_hFull, 1, NULL); 	
		SetEvent(g_hEventWriter);
	}  

	WriterPrintGreen("编号为%d的写者结束写数据//end\n", GetCurrentThreadId());  
	return 0;  
}

//一个写者一个读者
void SingleReaderSingleWirterTest()
{  
	ConsolePrintBlue("\n----------- 模拟一个写者和一个读者之间访问环形队列操作 ---------\n");
	
	HANDLE hThread[2]; 
	g_i = g_j = 0; 
	nDataR = nDataW = 0;

	InitializeCriticalSection(&g_cs);    //初始化g_cs的成员 
	
	g_hEmpty = CreateSemaphore(NULL, QUEUE_LEN, QUEUE_LEN, NULL);  //初始信号量为满,最大信号量为环形队列总个数 
	g_hFull = CreateSemaphore(NULL, 0, QUEUE_LEN, NULL);   //初始信号量为空,最大信号量为环形队列总个数  

	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);  

	WaitForMultipleObjects(2, hThread, TRUE, INFINITE);  
	
	for (int i = 0; i < 2; i++)  
	{
		CloseHandle(hThread[i]); 
	}
	CloseHandle(g_hEmpty);  
	CloseHandle(g_hFull);  
	
	ConsolePrintBlue("循环队列中保存的数为:\n");
	for (int i = 0; i < QUEUE_LEN; i++)
	{
		printf("%-6d", g_queue[i]);
	}
	printf("\n");

	DeleteCriticalSection(&g_cs);//删除关键段

	ConsolePrintBlue("\\----- end ------\n\n\n");
}

//一个写者十个读者
void MultiReaderSingleWirterTest()
{
	ConsolePrintBlue("\n----------- 模拟一个写者和多个读者之间访问缓形队列操作 ---------\n");
	
	g_i = g_j = 0;  
	HANDLE hThreadR[10];
	HANDLE hThreadW;
	nDataR = nDataW = 0;

	InitializeCriticalSection(&g_cs);  

	g_hEmpty = CreateSemaphore(NULL, 1, QUEUE_LEN, NULL);  
	g_hFull = CreateSemaphore(NULL, 0, QUEUE_LEN, NULL);  
	g_hEventReader = CreateEvent(NULL, false, true, NULL);        //设置事件,每次仅能一个读者读

	for (int i = 0; i < 10; i++)
	{
		hThreadR[i] = (HANDLE)_beginthreadex(NULL, 0, MultiReaderThreadFun, NULL, 0, NULL); 
	} 

	hThreadW = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);  

	WaitForSingleObject(hThreadW, INFINITE);
	WaitForMultipleObjects(10, hThreadR, TRUE, INFINITE);  

	for (int i = 0; i < 10; i++)  
	{	
		CloseHandle(hThreadR[i]); 
	}
	CloseHandle(hThreadW);
	CloseHandle(g_hEmpty);  
	CloseHandle(g_hFull);  
	
	ConsolePrintBlue("循环队列中保存的数为:\n");
	for (int i = 0; i < QUEUE_LEN; i++)
	{
		printf("%-6d", g_queue[i]);
	}
	printf("\n");

	DeleteCriticalSection(&g_cs);  

	ConsolePrintBlue("\\----- end ------\n\n\n");
}

//十个写者十个读者
void MultiReaderMultiReaderWriterTest() 
{
	ConsolePrintBlue("\n----------- 模拟多个写者和多个读者之间访问环形队列操作 ---------\n");
	g_i = g_j = 0;  
	HANDLE hThreadR[10];
	HANDLE hThreadW[10];
	nDataR = nDataW = 0;

	InitializeCriticalSection(&g_cs);  
 
	g_hEventReader = CreateEvent(NULL, false, true, NULL);        //设置事件,每次仅能一个读者读
	g_hEventWriter = CreateEvent(NULL, false, true, NULL);        //设置事件,每次仅能一个写者写
	g_hEmpty = CreateSemaphore(NULL, 1, QUEUE_LEN, NULL);         //初始计数为一,最大计数为十
	g_hFull = CreateSemaphore(NULL, 0, QUEUE_LEN, NULL);          //初始计数为零,最大计数为十

	for (int i = 0; i < 10; i++)
	{
		hThreadR[i] = (HANDLE)_beginthreadex(NULL, 0, MultiReaderThreadFun, NULL, 0, NULL); 
	} 
	for(int i = 0; i < 10; i++)
	{
		hThreadW[i] = (HANDLE)_beginthreadex(NULL, 0, MultiWriterThreadFun, NULL, 0, NULL);  
	}
	
	WaitForMultipleObjects(10, hThreadR, TRUE, INFINITE);  
	WaitForMultipleObjects(10, hThreadW, TRUE, INFINITE);

	for (int i = 0; i < 10; i++)  
	{	
		CloseHandle(hThreadR[i]); 
		CloseHandle(hThreadW[i]);
	}
	CloseHandle(g_hEmpty);  
	CloseHandle(g_hFull);  
	
	ConsolePrintBlue("循环队列中保存的数为:\n");
	for (int i = 0; i < QUEUE_LEN; i++)
	{
		printf("%-6d", g_queue[i]);
	}
	printf("\n");

	DeleteCriticalSection(&g_cs);  

	ConsolePrintBlue("\\----- end ------\n\n\n");	
}

void main()  
{  

	ConsolePrintBlue("----------- 基于win32平台下编写多线程操作 -----------\n\n");
	
	//创建线程,关闭线程,挂起线程
	ConsolePrintBlue("\n\n\n----------- 1:创建线程,关闭线程,挂起线程 -----------\n\n");
	ThreadexTest();

	//使用临界资源,互斥锁,信号量,事件
	ConsolePrintBlue("\n\n\n\n\n----------- 2:使用临界资源,互斥锁,信号量,事件 -----------\n\n");
	CriticalSectionTest();
 	SrwLockTest();
 	SemaphoreTest();
 	EventTest();

	//读者写者问题
	ConsolePrintBlue("\n\n\n\n\n----------- 3:读者写者问题 -----------\n\n");
 	SingleReaderSingleWirterTest();
 	MultiReaderSingleWirterTest();
	MultiReaderMultiReaderWriterTest();
} 
           

继续阅读