windows线程同步之关键段(critical section)

windows线程同步之关键段(critical section)
    关键段(critical section)是一小段代码,在它执行之前需要独占对一些共享资源的访问权。这种方式可以让多行代码以“原子方式”来对资源进行操控。这里的原子方式指的是代码知道除了当前线程外,没有其他的任何线程会同时访问该资源,当然,系统仍然可以暂停当前线程去调度其他线程。但是,在当前线程离开关键段之前,系统不会去调度任何想要访问统一资源的其他线程。

    下面是一段(共享资源被破坏)示例代码

//两个线程的共享资源
const int COUNT = 10;
INT g_nSum = 0;
CRITICAL_SECTION g_cs;

//线程1
DWORD WINAPI FirstThread(PVOID pvParam)
{
	EnterCriticalSection(&g_cs);
	g_nSum = 0;
	for (int n = 1; n<= COUNT; n++)
	{
		g_nSum += n;
	}
	LeaveCriticalSection(&g_cs);
	return g_nSum;
}

//线程2
DWORD WINAPI SecondThread(PVOID pvParam)
{
	EnterCriticalSection(&g_cs);
	g_nSum = 0;
	for (int n = 1; n <= COUNT; n++)
	{
		g_nSum += n;
	}
	LeaveCriticalSection(&g_cs);
	return g_nSum;
}
   我们先在代码中定义一个g_cs的CRITICAL_SECTION数据结构,然后把任何需要访问的共享资源(这里g_nSum)的代码放在EnterCriticalSection和LeaveCriticalSection之间。如果忘了哪怕是一个地方,共享资源就有可能被破坏。

1、 我们使用CREATE_SECTION的时候,必须先对CREATE_SECTION成员进行初始化。下面的函数用来对结构进行初始化:
InitializeCriticalSection(&g_cs);

通过 这个函数对CREATE_SECTION结构成员进行初始化,由于这个函数只是设置一些成员变量而已,不可能失败,因此返回值是void。

2、当知道线程不在需要访问共享资源的时候,我们应该调用下面的函数来清理CREATE_SEATION结构:

DeleteCriticalSection(&g_cs);

DeleteCriticalSection会重置结构成员中的变量。很自然,如果还有线程正在使用一个关键段,那么当然不应该删除它。

3、EnterCriticalSection函数会检查CREATE_SEATION结构中的成员变量,这些变量表示是否有线程正在访问资源,以及哪个线程正在访问资源。

    如果没有线程在访问资源,那么EnterCriticalSection会更新成员变量,表示调用的线程已获得对资源的访问,并立即返回。

    如果成员变量表示调用线程已经获准访问资源,那么EnterCriticalSection会更新变量,以表示调用线程被获准访问的次数,并立即返回,这种情况非常少见,只有当线程调用LeaveCriticalSection之前连续调用EnterCriticalSection两次以上才会发生。

    如果成员变量有一个(调用线程之外的其他)线程已经获准访问资源,那么EnterCriticalSection会使用一个事件内核对象来把调用线程切换到等待状态,这不会浪费任何CPU的时间,系统会记住这个线程要访问这个资源,一旦当前正在访问资源的线程调用了LeaveCriticalSection,系统会自动更新CREATE_SEATION的成员变量并将等待中的线程切换回可调度状态。

    实际上对EnterCriticalSection的调用最终会超时并引发异常。导致超时的时间长度用下面的这个注册表子项中包含的CriticalSectionTimeout值决定:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager这个值以秒为单位,默认值是2592000秒,大约30天

4、我们可以用TryEnterCriticalSection来代替EnterCriticalSection

    BOOL TryEnterCriticalSection(PCREATE_SECTION pcs);

    这个函数不会让调用线程进入等待状态,它会通过返回值来表示调用线程是否获准访问资源。因此如果TryEnterCriticalSection发现资源正在被其他线程访问,那么它会返回FALSE,其它情况下,它会返回TRUE。每个返回TRUE的TryEnterCriticalSection调用必须有一个对应的LeaveCriticalSection。

5、LeaveCriticalSection会检查CREATE_SECTION内部结构成员变量并将计数器减1,计数器代表调用线程获准访问共享资源的次数,如果计数器大于0,LeaveCriticalSection会直接返回,不执行任何操作。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值