如果我在下面显示的其他条件,我可以把关键部分放在许多中吗?
示例1
somefunction()
{
EnterCriticalSection(&(g_variable));
if (...)
{
if (...)
{
...
}
else
{
...
if (...)
{...}
else if (...)
{...}
LeaveCriticalSection(&(g_variable));
}
}
else
{
...
}
}
或像这样嵌套:
示例2
EnterCriticalSection(&g_List);
EnterCriticalSection(&g_Variable);
...
LeaveCriticalSection(&g_List);
LeaveCriticalSection(&g_Variable);
提前感谢您的帮助。
答案 0 :(得分:2)
在例1中,这是一个坏习惯。更好的威胁关键部分作为代码块
EnterCriticalSection(&g_Variable);
{
....
}
LeaveCriticalSection(&g_Variable);
更好的是,使用范围CS类:
class CScopeCS{
CRITICAL_SECTION& m_cs;
public:
CScopeCS(CRITICAL_SECTION& cs):m_cs(cs){
EnterCriticalSection(cs);
}
~CScopeCS(){
LeaveCriticalSection(m_cs);
}
}
当从临界区块退出时,它将自动调用析构函数。
{
CScopeCS scopeLock(g_cs);
....
}//end of critical section
在示例2中,它会像您编写的那样工作,但最好先保留最后一个:
EnterCriticalSection(&g_List);
EnterCriticalSection(&g_Variable);
...
LeaveCriticalSection(&g_Variable);
LeaveCriticalSection(&g_List);
但是您必须在代码中以相同的顺序使用两个关键部分以防止死锁。 (即第一个g_List然后是g_Variable)如果你已经输入了g_Variable并且想要同时输入g_List,你必须保留g_Variable并按顺序将它们带走。
答案 1 :(得分:2)
简短回答:是的,你可以。但使用Enter / LeaveCriticalSection对很容易出错。您自己的代码显示,在获取顶部的关键部分后,有一些代码路径,其中临界区未使用LeaveCriticalSection释放。其中一条路径是第一条if语句的else-block被采用的地方,而另一条更阴险的路径就是当中间的某些代码抛出异常时。
您将问题标记为C ++;如果C ++ 11可用,那么有一个很好的选择:标准头中的类,如recursive_mutex和lock_guard。你的代码看起来像这样:
recursive_mutex g_variable;
someFunction()
{
lock_guard<recursive_mutex> lock(g_variable);
if (...)
...
else
...
}
现在您可以保证在离开someFunction()时释放互斥锁。而且你必须输入更少,你的代码也是可移植的。
答案 2 :(得分:2)
您可以执行您在问题中显示的内容。至少在我看来,你应该做什么(因为你正在使用C ++)是使用RAII包装器自动获取LeaveCriticalSection调用以匹配你的EnterCriticalSection调用。
class crit_sect {
CRITICAL_SECTION cs;
void lock() { EnterCriticalSection(&cs); }
void unlock() { LeaveCriticalSection(&cs); }
friend class lock;
crit_sect(crit_sect const &); /* = delete; */
crit_sect &operator=(crit_sect const &other); /* = delete; */
public:
crit_sect() { InitializeCriticalSection(&cs); }
~crit_sect() { DeleteCriticalSection(&cs); }
};
class lock {
crit_sect &cs;
public:
lock(crit_sect &c) : cs(c) { cs.lock(); }
~lock() { cs.unlock(); }
};
使用这些,你有类似的东西:
if (whatever) {
lock list_lock(g_List);
lock var_lock(g_Variable);
// ...
}
...当执行离开定义了两个锁的范围时,析构函数将执行,自动解锁关键部分。这方便又方便;如果您正在使用异常,则变得更加重要,因为这意味着如果您通过异常而不是通过正常执行退出范围,关键部分仍将被解锁。