关键部分,如果是多线程应用程序中的其他条件

critical section and if ,else condition in multithreaded app

本文关键字:应用程序 其他 条件 多线程 键部 如果      更新时间:2023-10-16

如果我以下所示,我可以将关键部分放在许多条件下吗?

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

事先感谢您的帮助。

can 做的事情与您应该做的事情有所区别。

can 做您在问题中显示的事情。至少在我看来,您的应该做的事情(因为您使用的是C )是使用RAII包装器来自动获取您的LeaveCricitalSection呼叫以匹配您的肠cricationalliticalsection呼叫。

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);
// ...
}

...并且当执行留下定义两个锁的范围时,将执行驱动器,自动解锁关键部分。这很方便;如果您使用异常,它变得更加重要,因为这意味着如果您通过异常而不是通过正常执行退出范围,那么关键部分仍将被解锁。

简短答案:是的,您可以。但是很容易用成对的Enter/LeaveCricection犯错误。您自己的代码表明,在顶部将关键部分放在顶部之后,在某些代码路径中未释放临界部分的代码路径。其中一条路径是第一个if statement的其他块的地方,而另一个更阴险的路径是当两者之间的某些代码引发异常时。

您将问题标记为C ;如果可用C 11,则有一个绝佳的选择:标准标头的类,例如Recursive_mutex和Lock_Guard。您的代码看起来像这样:

recursive_mutex g_variable;
someFunction()
{
    lock_guard<recursive_mutex> lock(g_variable);
    if (...)
        ...
    else
        ...
}

现在,您可以保证二线释放()。而且您必须少输入,并且您的代码也是可移植的。

在示例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并按顺序进行操作。

相关文章: