Windows线程同步(一):临界区对象

为什么使用线程同步?

同步可以保证在一个时间内只有一个线程对某个资源(如操作系统资源等共享资源)有控制权。共享资源包括全局变量、公共数据成员或者句柄等。同步还可以使得有关联交互作用的代码按一定的顺序执行。

线程同步的方式?

同步对象有:CRITICAL_SECTION (临界区),Event(事件),Mutex(互斥对象),Semaphores(信号量)。

本文重点讲解CRITICAL_SECTION (临界区)。

临界区,说白了,就是“锁”。看过星爷的《破坏王》的朋友都知道,那个送外卖的小子,就是靠自创绝招“无敌风火轮”将大师兄打败,抱得美人归。“无敌风火轮”的本质就是:锁!

怎么锁?

这里有四个关键函数:InitializeCriticalSection  EnterCriticalSection  LeaveCriticalSection  DeleteCriticalSection来完成此机制。

使用临界区对象的时候,首先要定义一个临界区对象CriticalSection:
CRITICAL_SECTION CriticalSection;

然后,初始化该对象:InitializeCriticalSection(&CriticalSection);

如果一段程序代码需要对某个资源进行同步保护,则这是一段临界区代码。在进入该临界区代码前调用EnterCriticalSection函数,这样,其他线程都不能执行该段代码,若它们试图执行就会被阻塞。

完成临界区的执行之后,调用LeaveCriticalSection函数,其他的线程就可以继续执行该段代码。


简要实例

下面的代码中,如果不加CRITICAL_SECTION ,有可能造成在线程1给data设置完名字后,线程2给data设置年龄,造成了数据紊乱,所以有必要使用同步机制,将其锁住,保证数据的安全。

class Data
{
private:
	CString Name;
	int Age;
public:
	void SetName(const CString& name)
	{
		Name = name;
	}
	
	void SetAge(int age)
	{
		Age = age;
	}
	
	void GetName(CString &name)
	{
		name = Name;
	}
	
	void GetAge(int &age)
	{
		age = Age;
	}
};

Data g_data; //全局变量
CRITICAL_SECTION CriticalSection; 

//线程函数
DWORD WINAPI ThreadProc( LPVOID lpParameter )
{
	EnterCriticalSection(&CriticalSection); 
	data.SetName("赵星星");
	data.SetAge(20);
	LeaveCriticalSection(&CriticalSection);
}

int main()
{

    InitializeCriticalSection(&CriticalSection); 
	
    //创建线程,执行线程函数
	//......
	
	DeleteCriticalSection(&CriticalSection);

	return 0;
}
真锁?假锁?

可以定义CRITICAL_SECTION 数组:CRITICAL_SECTION g_Critical[10];

CRITICAL_SECTION 没有超时的概念,如果函数LeaveCriticalSection不被调用,则其他线程将无限期的等待。容易造成死锁。

CRITICAL_SECTION 属于轻量级的线程同步对象,相对于mutex来说,它的效率会高很多。mutex可以用于进程之间的同步,CRITICAL_SECTION只在同一个进程有效。

实际上,CRITICAL_SECTION 锁的是代码段,如果代码段中有对资源的占用,只是间接的锁住了该资源,我们也可以称之为“假锁”。


参考:

1、《MFC教程》

2、 csdn精彩讨论



你可能感兴趣的:(VC/MFC)