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();
}