动力设备网 加入收藏  -  设为首页
您的位置:动力设备网 > 科技 > 正文
ccriticalsection 用法 为什么是未定义标识符
ccriticalsection 用法 为什么是未定义标识符
提示:

ccriticalsection 用法 为什么是未定义标识符

CCriticalSection是对关键段CRITICAL_SECTION的封装。

关键段(critival section)是一小段代码,他在执行之前需要独占对一些共享资源的访问权。这种方式可以让多行代码以“原子方式”来对资源进行操控。这里的“原子方式”,指的是代码知道除了当前线程之外没有其他任何线程会同时访问该资源。当然,系统仍然可以暂停当前线程去调度其他线程。但是,在当前线程离开关键段之前,系统是不会去调度任何想要访问同一资源的其他线程的。
例如:如果两个线程同时访问一个链表,一个线程可能会在另一个线程搜寻元素的同时向链表中添加一个元素,将导致搜索结果不正确;还有可能两个线程同时向链表中添加元素,这种情况会变的更加混乱;甚至一个线程搜索的时候,另一个线程删除了链表节点,将直接导致程序崩溃。
解决这个问题,我们可以先在代码中定义一个CRITICAL_SECTION数据结构m_sect,然后把任何需要访问共享资源的代码放在EnterCriticalSection和LeaveCriticalSection之间。

[cpp] view plain copy print?
EnterCriticalSection(&m_sect);
// 共享资源的代码段....

LeaveCriticalSection(&m_sect);

一个 CRITICAL_SECTION结构就像是飞机上的一个卫生间,而马桶则是我们想要保护的资源(用EnterCriticalSection和LeaveCriticalSection组成的围墙包围住“马桶”)。由于卫生间很小,因此在同一时刻只允许一个人在卫生间内使用马桶(在同一时刻只允许一个线程在关键段中使用被保护资源)。
如果有多个总是应该在一起使用的资源,那么我们可以把他们放在同一个“卫生间”中:只需要创建一个CRITICAL_SECTION结构来保护所有这些资源。

关于关键段,需要掌握以下几点:
1、任何要访问共享资源的代码,都必须包含在EnterCriticalSection和LeaveCriticalSection之间。如果忘了哪怕是一个地方,共享资源就有可能被破坏。忘记调用EnterCriticalSection和LeaveCriticalSection,就好像是未经许可就强制进入卫生间一样,线程强行进入并对资源进行操控。只要有一个线程有这种粗暴的行为,资源就会被破坏。
2、关键段CRITICAL_SECTION是个未公开的结构,因为Microsoft认为开发人员不需要理解这个结构的细节。对我们来说,不需要知道这个结构中的成员变量,我们绝对不应该在编写代码的时候用到他的成员。
3、为了对CRITICAL_SECTION结构进行操控,我们必须调用Windows API函数,传入结构的地址。(注意是地址!)也就是说,如果该CRITICAL_SECTION结构生命周期没有结束,那么可以将该结构地址通过自己喜欢的任何方式传给任何线程。
4、在任何线程试图访问被保护的资源之前,必须对CRITICAL_SECTION结构的内部成员进程初始化。我们不知道内部成员,但可以调用Windows函数实现:VOID WINAPI InitializeCriticalSection(__out LPCRITICAL_SECTION lpCriticalSection);
5、当线程不再需要访问共享资源的时候,应调用下面的函数来清理该结构:VOID WINAPI DeleteCriticalSection(__inout LPCRITICAL_SECTION lpCriticalSection);

6、其实CRITICAL_SECTION并不知道什么是共享资源,也不会智能保护共享资源。其根本是,同一个时刻如果有多个线程调用EnterCriticalSection的时候,只有一个线程返回,其余线程则暂停执行,等待前面线程调用LeaveCriticalSection之后再执行。

7、可以看出,进入关键段是没有超时设定的,好像永远不会超时。实际上,对EnterCriticalSection的调用也会超时并引发异常。超时的时间长度由下面这个注册表子项中包含的CriticalSectionTimeout值决定:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
这个值以秒为单位,他的默认值为2592000秒,大约30天。

8、同一个线程可以随便进入用一个关键段N次,也就是说同一个线程调用EnterCriticalSection无论几次都会返回。不同线程是否能够进入关键段,要看EnterCriticalSection的参数(CRITICAL_SECTION结构的地址)之前是否有线程进入过。要记住:飞机上的卫生间有多个,你可以随便进入无人的卫生间,不能进入有人的卫生间。


弄明白了CRITICAL_SECTION之后,使用CCriticalSection非常方便,如虎添翼。看代码:
//头文件
[cpp] view plain copy print?
class CCriticalSection : public CSyncObjet
{...
public:
CRITICAL_SECTION m_sect;
public:
BOOL Unlock();
BOOL Lock();
BOOL Lock(DWORD dwTimeout);
...
}

// 构造函数
[cpp] view plain copy print?
CCriticalSection::CCriticalSection() : CSyncObject(NULL)
{
HRESULT hr = S_OK;
if (!InitializeCriticalSectionAndSpinCount(&m_sect, 0))//可以理解为InitializeCriticalSection,为了效率,加了一个旋转锁。
{
hr = HRESULT_FROM_WIN32(GetLastError());
}

if (FAILED(hr))
{
AtlThrow(hr);
}
}


//进入关键段
[cpp] view plain copy print?
BOOL CCriticalSection::Lock()
{
::EnterCriticalSection(&m_sect);

return TRUE;
}


// 离开关键段
[cpp] view plain copy print?
BOOL CCriticalSection::Unlock()
{
::LeaveCriticalSection(&m_sect);

return TRUE;
}

// 析构
[cpp] view plain copy print?
CCriticalSection::~CCriticalSection()
{
::DeleteCriticalSection(&m_sect);
}

Critical Section和Mutex的不同点
提示:

Critical Section和Mutex的不同点

1.Critical Section A.速度快 B.不能用于不同进程 C.不能进行资源统计(每次只可以有一个线程对共享资源进行存取) 2.Mutex A.速度慢 B.可用于不同进程 C.不能进行资源统计 3.Semaphore A.速度慢 B.可用于不同进程 C.可进行资源统计(可以让一个或超过一个线程对共享资源进行存取) 4.Event A.速度慢 B.可用于不同进程 C.可进行资源统计

什么是进程的互斥?为什么会有进程的互斥要求?
提示:

什么是进程的互斥?为什么会有进程的互斥要求?

两个或两个以上的进程,不能同时进入关于同一组共享变量的临界区域,否则可能发生与时间有关的错误,这种现象被称作进程互斥.在多道程序环境下,存在着临界资源,它是指多进程存在时必须互斥访问的资源.也就是某一时刻不允许多个进程同时访问,只能单个进程的访问.我们把这些程序的片段称作临界区或临界段,它存在的目的是有效的防止竞争条件又能保证最大化使用共享数据.而这些并发进程必须有好的解决方案,才能防止出现以下情况:多个进程同时处于临界区,临界区外的进程阻塞其他的进程,有些进程在临界区外无休止的等待.除此以外,这些方案还不能对CPU的速度和数目做出任何的假设.只有满足了这些条件,才是一个好的解决方案.访问临界资源的循环进程可以这样来描述:Repeat entry section Critical sections; exit section Remainder sectioni; Until false 编辑本段实现进程互斥 为实现进程互斥,可以利用软件的方法,也可以在系统中设置专门的同步机制来协调多个进程,但是所有的同步机制应该遵循四大准则:1.空闲让进 当临界资源处于空闲状态,允许一个请求进入临界区的进程立即进入临界区,从 而有效的利用资源.2.忙则等待 已经有进程进入临界区时,意味着相应的临界资源正在被访问,所以其他准备进 入临界区的进程必须等待,来保证多进程互斥.3.有限等待 对要求访问临界资源的进程,应该保证该进程能在有效的时间内进入临界区,防 止死等状态.4.让权等待 当进程不能进入临界区,应该立即释放处理机,防止进程忙等待.早期解决进程互斥问题有软件的方法和硬件的方法,如:严格轮换法,Peterson的解决方案,TSL指令,Swap指令都可以实现进程的互斥,不过它们都有一定的缺陷,这里就不一一详细说明,而后来Dijkstra提出的信号量机制则更好的解决了互斥问题.解决进程互斥还有管程,进程消息通信等方式.希望可以解决你的疑惑!

什么是进程的互斥?为什么会有进程的互斥要求?
提示:

什么是进程的互斥?为什么会有进程的互斥要求?

两个或两个以上的进程,不能同时进入关于同一组共享变量的临界区域,否则可能发生与时间有关的错误,这种现象被称作进程互斥. 在多道程序环境下,存在着临界资源,它是指多进程存在时必须互斥访问的资源。也就是某一时刻不允许多个进程同时访问,只能单个进程的访问。我们把这些程序的片段称作临界区或临界段,它存在的目的是有效的防止竞争条件又能保证最大化使用共享数据。而这些并发进程必须有好的解决方案,才能防止出现以下情况:多个进程同时处于临界区,临界区外的进程阻塞其他的进程,有些进程在临界区外无休止的等待。除此以外,这些方案还不能对CPU的速度和数目做出任何的假设。只有满足了这些条件,才是一个好的解决方案。 访问临界资源的循环进程可以这样来描述: Repeat entry section Critical sections; exit section Remainder sectioni; Until false 编辑本段实现进程互斥 为实现进程互斥,可以利用软件的方法,也可以在系统中设置专门的同步机制来协调多个进程,但是所有的同步机制应该遵循四大准则: 1.空闲让进 当临界资源处于空闲状态,允许一个请求进入临界区的进程立即进入临界区,从 而有效的利用资源。 2.忙则等待 已经有进程进入临界区时,意味着相应的临界资源正在被访问,所以其他准备进 入临界区的进程必须等待,来保证多进程互斥。 3.有限等待 对要求访问临界资源的进程,应该保证该进程能在有效的时间内进入临界区,防 止死等状态。 4.让权等待 当进程不能进入临界区,应该立即释放处理机,防止进程忙等待。 早期解决进程互斥问题有软件的方法和硬件的方法,如:严格轮换法,Peterson的解决方案,TSL指令,Swap指令都可以实现进程的互斥,不过它们都有一定的缺陷,这里就不一一详细说明,而后来Dijkstra提出的信号量机制则更好的解决了互斥问题。 解决进程互斥还有管程,进程消息通信等方式. 希望可以解决你的疑惑!