【问题标题】:pthread mutex locking variables used in statements语句中使用的 pthread 互斥锁变量
【发布时间】:2016-09-05 03:48:33
【问题描述】:

首先,我有一种直觉,在 if 语句中,如果我正在使用该变量,它会被视为读取该变量,所以我也应该在那里用互斥锁锁定它(如果另一个 pthread 可能正在做一些事情用它)。我应该锁定它吗?

下面给出简化的示例情况。

在一个线程中,我使用以下语句:

if(event){
  // Should I or should I not lock event here to use it
  // inside if statement?
  pthread_mutex_lock(&mutex_event);
  event = 0;
  pthread_mutex_unlock(&mutex_event);
  // blah blah code here
  // blah blah code here
  // blah blah code here
}

在我正在做的另一个线程中

pthread_mutex_lock(&mutex_event);
event = 1;
pthread_mutex_unlock(&mutex_event);

第二个问题,如果我确实需要锁定它,我应该如何以优雅的程序员方式来做呢?换句话说,什么是一般约定。我不喜欢下面的想法,因为我必须等待“if”中的所有行执行才能再次解锁互斥锁。

pthread_mutex_lock(&mutex_event);
if(event){ 
  event = 0;
  // blah blah code here
  // blah blah code here
  // blah blah code here
}
pthread_mutex_unlock(&mutex_event);

我同意这个想法,但它可能看起来更漂亮:

pthread_mutex_lock(&mutex_event);
if(event){    
  event = 0;
  pthread_mutex_unlock(&mutex_event);
  // blah blah code here
  // blah blah code here
  // blah blah code here
}
else
{
  pthread_mutex_unlock(&mutex_event);
}

我发现使用 while 循环会变得更棘手,这是我得到的原始解决方案:

pthread_mutex_lock(&mutex_event);
store_event = event; // store_event is local
pthread_mutex_unlock(&mutex_event);
while(store_event){ 
  // blah blah code here
  // blah blah code here
  // blah blah code here
}

【问题讨论】:

    标签: c linux pthreads posix mutex


    【解决方案1】:

    每个对共享变量的访问——写和读——都应该受到保护。互斥锁还有多少是个人问题 - 平衡开销、使用变量的原子性和代码的清晰度。

    另外,你不想在受保护的区域里花很长时间,所以如果你在一段很长的代码中同步一个变量两次,你不想锁定整个大段受限。

    有些读取明显有问题:

    pthread_mutex_lock(&mutex_event);
    if(event){ 
      event = 0;
      pthread_mutex_unlock(&mutex_event);
      // blah blah code here
      // blah blah code here
      // blah blah code here
    }
    else pthread_mutex_unlock(&mutex_event); //awful, a hundred lines below the opening.
    

    在这种情况下,最好留下不同的“同步区域”,并对变量的本地副本进行操作。

    pthread_mutex_lock(&mutex_event);
    event_copy = event;
    data_copy = data;
    state_copy = state;
    pthread_mutex_unlock(&mutex_event);
    
    if(event_copy){ 
      // blah blah code here
      // blah blah code here
      event_copy = 0;
      // blah blah code here
    }
    // blah blah code here
    
    pthread_mutex_lock(&mutex_event);
    event = event_copy;
    data = data_copy;
    state = state_copy;
    pthread_mutex_unlock(&mutex_event);
    

    等等。

    frequent 用于给定变量的这种方式不需要病房,没有忘记某些解锁的风险(例如缺少“else”语句!),并且您将工作捆绑在一起,最大限度地减少等待时间在互斥体中或锁定/解锁它们。

    还要记住:不要将同步数据丢失到缓存中,所有线程间变量都应该声明为volatile。否则,您的event 可能需要很长时间才能从一个线程传播到另一个线程。但是使用volatile 会破坏编译器的许多优化。通过制作非易失性本地副本,您可以减少围绕易失性变量所做的工作量,并允许优化器在所有副本上疯狂运行,而不会造成破坏。

    【讨论】:

    • 谢谢。现在我确定使用哪种方式了。
    • @etugcey: ...另外,当您的当前线程覆盖另一个线程新写入的event = 1 时,您会感到非常意外,因为两个事件会以快速顺序触发...但这是另一个问题的主题。 (提示:单向变量,writer threadreader thread。)
    • @SF。事件队列是这个问题的自然解决方案。
    • @SF。您能否扩展“所有线程间变量都应声明为易失性”的说法?这是一个很大的主张,可能会被误解或误用,所以更多的解释和支持会很好。
    • @SF 请对 volatile 进行扩展,我想了解更多。
    【解决方案2】:

    是的,您确实需要对所有读取进行同步。

    对于while() 循环,您可以使用此模式:

    pthread_mutex_lock(&mutex_event);
    while(event) {
      pthread_mutex_unlock(&mutex_event);
      // blah blah code here
      // blah blah code here
      // blah blah code here
      pthread_mutex_lock(&mutex_event);
    }
    pthread_mutex_unlock(&mutex_event);
    

    ..所以锁总是保持在这个条件下。

    【讨论】:

      【解决方案3】:

      是的,您应该始终在读取或写入受保护变量之前锁定互斥锁。为避免代码混乱,同时尽量减少锁定时间,您应该将事件信息移动到可以在互斥锁解锁后使用的局部变量中,像这样

      int do_blah = 0;
      
      pthread_mutex_lock(&mutex_event);
      if(event){
          event = 0;
          do_blah = 1;
      }
      pthread_mutex_unlock(&mutex_event);
      
      if ( do_blah ) {
          // blah blah code here
          // blah blah code here
          // blah blah code here
      }
      

      【讨论】:

      • 感谢您的回答。你怎么看,把加锁、读、解锁过程变成一个函数,在if语句中调用函数?
      • @etugcey 以防万一——如果与特定操作相关的共享状态包含多个变量(通常如此),则您的锁必须保护定义共享状态的整个变量集。示例:N 共享元素的求和——求和时,所有N 必须处于锁定状态。 (嗯,你可以解锁你已经数过的元素,但通常并不容易)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 1970-01-01
      • 2012-04-20
      • 2012-08-28
      • 1970-01-01
      • 2015-06-19
      • 2013-06-06
      相关资源
      最近更新 更多