语句中使用的c-pthread互斥锁锁定变量



首先,我有一种直觉,在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
}

对共享变量的每次访问-写和读-都应该受到保护。互斥体围绕的其他内容是一个单独的问题——平衡开销、使用变量的原子性和代码的清晰度。

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

显然有些读数有问题:

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

等等

通过这种方式,频繁对给定变量的使用不需要病房,也没有忘记解锁的风险(比如缺少"else"语句!),并且可以将工作捆绑在一起,最大限度地减少在互斥锁中等待或锁定/解锁它们的时间。

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

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

对于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);

所以锁总是保持在这种状态。

是的,在读取或写入受保护的变量之前,您应该始终锁定互斥对象。为了避免混乱的代码,同时最大限度地减少锁定时间,您应该将事件信息移动到一个本地变量中,该变量可以在互斥对象解锁后使用,比如这个

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
}

最新更新