Win32 临界区

1.线程安全问题

现在我们从第一堂课开始思考关于线程的问题

1.单线程执行对线程任务

前面我们在编写一个计时器程序时,一个函数时实现数字的自减并显示,另一个是消息处理函数

此时如果我们不新建一个线程在实现数字自减的功能的话,就会出现消息处理函数线程被占用的问题,因此导致程序崩溃

2.开始、挂起、恢复、终止

这里的挂起和恢复功能没有什么好讲的,调用不同的韩式来实现就行了

如果此时我们想要实现两个线程对一个变量的操作,就会存在问题

前面我们知道了,如果两个线程同时启动,那么内核就会对他们就行不断地切换

并且在切换之前,会将当前线程中各个寄存器的数据存进ConText结构体中

在20ms后,再次切换到该线程时可以实现从前面的进程开始

现在我们创建了两个线程来实现对一个变量的操作

那么就要考虑到以下情况:

1.点击开始1,知道线程1执行完毕,我们再点击线程2,此时结果是正确的

2.点击开始1后,线程1还没执行完毕,我们就点击线程2,此时就相当于两个线程在切换执行,线程2读取变量进行操作后,时间片结束后又轮到线程1执行,但是线程1会POP出ConText结构体中的数据继续前面的进程进行操作,因此就会出现进程1少操作一次的问题

为了避免出现这种情况,我们就要使用临界区来进行限制

2.临界区的使用

 

 

3.怎样使用是最合理的

该场景获取令牌函数和归还令牌函数在循环当中,实现的功能是每一次循环获取一次令牌

然后实现对变量的操作,操作完毕后归还令牌

此时另一线程就可以获取令牌,实现操作。。。。。

因此场景一是正确的,可以实现对于多线程的运行

场景二是先获取令牌,而后完成循环,只有将循环完成后才归还令牌

然后另一线程还有获取令牌的机会

因此改场景是将多线程实现了逐个进行的目的,因此不正确

该场景只有线程1当中使用了临界区,但是在线程2中没有临界区的限制

因此就相当于另一线程无视令牌的存在,直接占用内核,因此不正确

多线程使用多全局变量的情况:

下面的代码哪里有问题:


全局变量X
全局变量Y
全局变量Z

线程1
DWORD WINAPI ThreadFunc(PVOID pvParam) 
{
   EnterCriticalSection(&g_cs);
   使用X
   使用Y
   LeaveCriticalSection(&g_cs);
   return(0);
}

线程2
DWORD WINAPI ThreadFunc(PVOID pvParam) 
{
   EnterCriticalSection(&g_cs);
   使用X
   使用Z
   LeaveCriticalSection(&g_cs);
   return(0);
}

线程3
DWORD WINAPI ThreadFunc(PVOID pvParam) 
{
   EnterCriticalSection(&g_cs);
   使用Y
   使用X
   LeaveCriticalSection(&g_cs);
   return(0);
}


解决方案:


CRITICAL_SECTION g_csX; 
CRITICAL_SECTION g_csY; 
CRITICAL_SECTION g_csZ; 

线程1
DWORD WINAPI ThreadFunc(PVOID pvParam) 
{
   EnterCriticalSection(&g_csX);
   使用X
   LeaveCriticalSection(&g_csX);
   EnterCriticalSection(&g_csY);
   使用Y
   LeaveCriticalSection(&g_csY);

   return(0);
}

线程2
DWORD WINAPI ThreadFunc(PVOID pvParam) 
{
   EnterCriticalSection(&g_csX);
   使用X
   LeaveCriticalSection(&g_csX);
   EnterCriticalSection(&g_csZ);
   使用Z
   LeaveCriticalSection(&g_csZ);

   return(0);
}

线程3
DWORD WINAPI ThreadFunc(PVOID pvParam) 
{
   EnterCriticalSection(&g_csX);
   使用X
   LeaveCriticalSection(&g_csX);
   return(0);
}

多线程想要使用不同的资源的时候,我们可以定义不同的令牌

这样就可以实现,某线程需要使用某资源时,获取该资源的指定令牌

待该线程归还令牌后,其他线程才能获取令牌,再使用资源

4.死锁

线程X拿B后在还没拿到A之前,时间片结束,来到线程Y,在时间片没结束之间拿到B,那么就出现了两个线程之间都不归还的情况,就造成了两个线程都无法继续的情况

解决办法就是将两个线程之间获取令牌归还令牌的顺序写成一样

这样一旦线程X拿到B,那么线程2就无法继续进行下去

#include<windows.h>
#include<stdio.h>

CRITICAL_SECTION cs_A;
CRITICAL_SECTION cs_B;


DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	EnterCriticalSection(&cs_A);
	Sleep(21);
	for(int i=0;i<1000;i++)
	{
		Sleep(1000);
		printf("1111:%d %d %d\n",cs_A.LockCount,cs_A.RecursionCount,cs_A.OwningThread);

		EnterCriticalSection(&cs_B);
	
		LeaveCriticalSection(&cs_B);
	}
	LeaveCriticalSection(&cs_A);
	return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
	EnterCriticalSection(&cs_B);
	for(int i=0;i<1000;i++)
	{
		//Sleep(1000);
		printf("2222:%d %d %d\n",cs_B.LockCount,cs_B.RecursionCount,cs_B.OwningThread);

		EnterCriticalSection(&cs_A);
	
		LeaveCriticalSection(&cs_A);
	}
	LeaveCriticalSection(&cs_B);
	return 0;
}




int main()
{
	InitializeCriticalSection(&cs_A);

	InitializeCriticalSection(&cs_B);
	
	HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);

	HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);



	CloseHandle(hThread1);

	CloseHandle(hThread2);


	Sleep(1000*10000);

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值