32win32编程基础——线程安全之临界区实现多线程抢红包实验

第一种代码实现,参考别人的代码,利用无限循环的标志:

//抢红包练习互斥
#include <windows.h>
#include "OutPut.h"
#include "resource1.h"
#include <stdio.h>

HINSTANCE hins;
HANDLE HMain;
CRITICAL_SECTION  ics;

//先用临界区实现抢红包
//后用互斥体实现抢红包

DWORD WINAPI  ThreadH1Proc( __in  LPVOID lpParameter){
	int flag = 1;
	TCHAR sz[20];
	int dwCount=0;
	int Count1=0;
	while(flag){
		EnterCriticalSection(&ics);
		GetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz,20);
		swscanf(sz,TEXT("%d"),&dwCount);
		if(dwCount>=50)
		{
			dwCount = dwCount-50;
			Count1 = Count1+50;
		}else{
				flag = 0;
		}
		swprintf(sz,TEXT("%d"),dwCount);
		SetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz);
		swprintf(sz,TEXT("%d"),Count1);
		SetDlgItemText(HWND(lpParameter),IDC_EDIT_H1,sz);
		LeaveCriticalSection(&ics);
		Sleep(100);
	}

	return 0;
}
DWORD WINAPI  ThreadH2Proc( __in  LPVOID lpParameter){
	int flag = 1;
	TCHAR sz[20];
	int dwCount=0;
	int Count1=0;
	while(flag){
		EnterCriticalSection(&ics);
		GetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz,20);
		swscanf(sz,TEXT("%d"),&dwCount);
		if(dwCount>=50)
		{
			dwCount = dwCount-50;
			Count1 = Count1+50;
		}else{
				flag = 0;
		}
		swprintf(sz,TEXT("%d"),dwCount);
		SetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz);
		swprintf(sz,TEXT("%d"),Count1);
		SetDlgItemText(HWND(lpParameter),IDC_EDIT_H2,sz);
		LeaveCriticalSection(&ics);
		Sleep(100);
	}

	return 0;
}
DWORD WINAPI  ThreadH3Proc( __in  LPVOID lpParameter){
	int flag = 1;
	TCHAR sz[20];
	int dwCount=0;
	int Count1=0;
	while(flag){
		EnterCriticalSection(&ics);
		GetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz,20);
		swscanf(sz,TEXT("%d"),&dwCount);
		if(dwCount>=50)
		{
			dwCount = dwCount-50;
			Count1 = Count1+50;
		}else{
				flag = 0;
		}
		swprintf(sz,TEXT("%d"),dwCount);
		SetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz);
		swprintf(sz,TEXT("%d"),Count1);
		SetDlgItemText(HWND(lpParameter),IDC_EDIT_H3,sz);
		LeaveCriticalSection(&ics);
		Sleep(100);
	}

	return 0;
}

//抢红包线程
DWORD WINAPI  ThreadMainProc( __in  LPVOID hwndDlg){
 
	HANDLE hand[3];

	InitializeCriticalSection(&ics);
	
	TCHAR sz[20];
	//取出红包的数量
	GetDlgItemText(HWND(hwndDlg),IDC_EDIT_ALL,sz,20);
	//初始化全局变量
	swscanf(sz,TEXT("%d"),&RedEvCount);
	//然后启动3个线程开始抢
	hand[0] = CreateThread(NULL,NULL,ThreadH1Proc,hwndDlg,0,NULL);
	hand[1] = CreateThread(NULL,NULL,ThreadH2Proc,hwndDlg,0,NULL);
	hand[2] = CreateThread(NULL,NULL,ThreadH3Proc,hwndDlg,0,NULL);

	WaitForSingleObject(hand[0],-1);
	WaitForSingleObject(hand[1],-1);
	WaitForSingleObject(hand[2],-1);

	CloseHandle(hand[0]);
	CloseHandle(hand[1]);
	CloseHandle(hand[2]);

	DeleteCriticalSection(&ics);

    return 0;
}
BOOL CALLBACK DialogProc(  HWND hwndDlg,   UINT uMsg,   WPARAM wParam, LPARAM lParam){

	switch(uMsg)
	{
		case WM_COMMAND:
		{
			WORD Id=LOWORD(wParam);
			WORD EventId = HIWORD(wParam);
			switch(Id)
			{
				case IDC_BUTTON_BEGIN:
					{
						HMain = ::CreateThread(NULL,NULL,ThreadMainProc,(LPVOID)hwndDlg,0,NULL);
					}
				default:
					{
						return FALSE;
					}

			}
			return 0;
		}
		case WM_CLOSE:
			{
				EndDialog(hwndDlg,0);
				return 0;
			}
		case WM_INITDIALOG:
			{
				SetDlgItemText(hwndDlg,IDC_EDIT_ALL,TEXT("0"));
				SetDlgItemText(hwndDlg,IDC_EDIT_H1,TEXT("0"));
				SetDlgItemText(hwndDlg,IDC_EDIT_H2,TEXT("0"));
				SetDlgItemText(hwndDlg,IDC_EDIT_H3,TEXT("0"));
				return 0;
			}
	}

	return FALSE;
};


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR  lpCmdLine,int  nCmdShow)
{
	//如果有界面的程序,主线程就是界面的,不要做什么逻辑操作,
	//重启新的线程做逻辑操作,不然界面容易卡死。
	hins = hInstance;
	

	DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,DialogProc);

    return 0;
}

第二种我自己写的使用全局变量,不知道为什么出错

//抢红包练习互斥
#include <windows.h>
#include "OutPut.h"
#include "resource1.h"
#include <stdio.h>

HINSTANCE hins;
HANDLE HMain;
CRITICAL_SECTION  ics;
int RedEvCount;
//先用临界区实现抢红包
//后用互斥体实现抢红包

DWORD WINAPI  ThreadH1Proc( __in  LPVOID lpParameter){
 
	//创建抢红包线程1
	TCHAR sz[20];
	int dwCount=0;

	//取出红包的数量,//转换为数字
	EnterCriticalSection(&ics);
	while(RedEvCount>=50)
	{
			RedEvCount = RedEvCount - 50;		
			//然后再转换为字符串
			swprintf(sz,TEXT("%d"),RedEvCount);
			//放到红包数量中
			SetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz);
			
			dwCount = dwCount+50;
			swprintf(sz,TEXT("%d"),dwCount);
			SetDlgItemText(HWND(lpParameter),IDC_EDIT_H1,sz);

			LeaveCriticalSection(&ics);
			Sleep(100);
	}
	ExitThread(0x11);

    return 0;
}
DWORD WINAPI  ThreadH2Proc( __in  LPVOID lpParameter){
 
	//创创建抢红包线程2
	//创建抢红包线程1
	TCHAR sz[20];
	int dwCount=0;
	EnterCriticalSection(&ics);
	while(RedEvCount>=50)
	{
			RedEvCount = RedEvCount - 50;		
			//然后再转换为字符串
			swprintf(sz,TEXT("%d"),RedEvCount);
			//放到红包数量中
			SetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz);

			dwCount = dwCount+50;
			swprintf(sz,TEXT("%d"),dwCount);
			SetDlgItemText(HWND(lpParameter),IDC_EDIT_H2,sz);

			LeaveCriticalSection(&ics);
			Sleep(100);
	}
	
	ExitThread(0x22);

    return 0;
}
DWORD WINAPI  ThreadH3Proc( __in  LPVOID lpParameter){
 
	//创建抢红包线程3
	TCHAR sz[20];
	int dwCount=0;

	EnterCriticalSection(&ics);
	while(RedEvCount>=50)
	{
			RedEvCount = RedEvCount - 50;		

			//然后再转换为字符串
			swprintf(sz,TEXT("%d"),RedEvCount);
			//放到红包数量中
			SetDlgItemText(HWND(lpParameter),IDC_EDIT_ALL,sz);

			dwCount = dwCount+50;
			swprintf(sz,TEXT("%d"),dwCount);
			SetDlgItemText(HWND(lpParameter),IDC_EDIT_H3,sz);
			LeaveCriticalSection(&ics);

			Sleep(100);
	}
	ExitThread(0x33);
    return 0;
}


//抢红包线程
DWORD WINAPI  ThreadMainProc( __in  LPVOID hwndDlg){
 
	HANDLE hand[3];

	InitializeCriticalSection(&ics);
	
	TCHAR sz[20];
	//取出红包的数量
	GetDlgItemText(HWND(hwndDlg),IDC_EDIT_ALL,sz,20);
	//初始化全局变量
	swscanf(sz,TEXT("%d"),&RedEvCount);
	//然后启动3个线程开始抢
	hand[0] = CreateThread(NULL,NULL,ThreadH1Proc,hwndDlg,0,NULL);
	hand[1] = CreateThread(NULL,NULL,ThreadH2Proc,hwndDlg,0,NULL);
	hand[2] = CreateThread(NULL,NULL,ThreadH3Proc,hwndDlg,0,NULL);

	WaitForSingleObject(hand[0],-1);
	WaitForSingleObject(hand[1],-1);
	WaitForSingleObject(hand[2],-1);

	CloseHandle(hand[0]);
	CloseHandle(hand[1]);
	CloseHandle(hand[2]);

	DeleteCriticalSection(&ics);

    return 0;
}
BOOL CALLBACK DialogProc(  HWND hwndDlg,   UINT uMsg,   WPARAM wParam, LPARAM lParam){

	switch(uMsg)
	{
		case WM_COMMAND:
		{
			WORD Id=LOWORD(wParam);
			WORD EventId = HIWORD(wParam);
			switch(Id)
			{
				case IDC_BUTTON_BEGIN:
					{
						HMain = ::CreateThread(NULL,NULL,ThreadMainProc,(LPVOID)hwndDlg,0,NULL);
					}
				default:
					{
						return FALSE;
					}

			}
			return 0;
		}
		case WM_CLOSE:
			{
				EndDialog(hwndDlg,0);
				return 0;
			}
		case WM_INITDIALOG:
			{
				SetDlgItemText(hwndDlg,IDC_EDIT_ALL,TEXT("0"));
				SetDlgItemText(hwndDlg,IDC_EDIT_H1,TEXT("0"));
				SetDlgItemText(hwndDlg,IDC_EDIT_H2,TEXT("0"));
				SetDlgItemText(hwndDlg,IDC_EDIT_H3,TEXT("0"));
				return 0;
			}
	}

	return FALSE;
};


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR  lpCmdLine,int  nCmdShow)
{
	//如果有界面的程序,主线程就是界面的,不要做什么逻辑操作,
	//重启新的线程做逻辑操作,不然界面容易卡死。
	hins = hInstance;
	

	DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,DialogProc);

    return 0;
}

 通过实验发现问题:

 

线程3红包变为850
线程3第0次抢到50放到自己的包里

线程2红包变为800
线程2第1次抢到50放到自己的包里

线程1红包变为750
线程1第1次抢到50放到自己的包里

线程3红包变为700
线程3第1次抢到50放到自己的包里

线程2红包变为650
线程2第2次抢到50放到自己的包里

线程1红包变为550
线程3红包变为550
线程1第2次抢到50放到自己的包里
线程3第2次抢到50放到自己的包里

线程2红包变为500
线程2第3次抢到50放到自己的包里

线程1红包变为450
线程1第3次抢到50放到自己的包里

线程3红包变为400
线程3第3次抢到50放到自己的包里

线程2红包变为300
线程1红包变为300
线程2第4次抢到50放到自己的包里
线程1第4次抢到50放到自己的包里

线程3红包变为250
线程3第4次抢到50放到自己的包里

线程2红包变为200
线程2第5次抢到50放到自己的包里

线程1红包变为150
线程1第5次抢到50放到自己的包里

线程3红包变为100
线程3第5次抢到50放到自己的包里

线程1红包变为50
线程2红包变为50
线程1第6次抢到50放到自己的包里
线程2第6次抢到50放到自己的包里

线程3红包变为0
线程3第6次抢到50放到自己的包里

  可能由于电脑是多核的原因,存在同时读取一段代码的可能。同时访问临界区,那么这个时候访问的全局变量的值就会相同。

posted @ 2023-11-02 22:35  一日学一日功  阅读(33)  评论(0)    收藏  举报