关键部分和if,否则多线程应用程序中的条件

时间:2014-01-22 18:18:33

标签: c++ multithreading critical-section

如果我在下面显示的其他条件,我可以把关键部分放在许多中吗?

示例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);

提前感谢您的帮助。

3 个答案:

答案 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);

// ...

}

...当执行离开定义了两个锁的范围时,析构函数将执行,自动解锁关键部分。这方便又方便;如果您正在使用异常,则变得更加重要,因为这意味着如果您通过异常而不是通过正常执行退出范围,关键部分仍将被解锁。