是在共享函数内部还是外部使用互斥锁

假设sharedFnc是在多个线程之间使用的函数:

void sharedFnc(){
   // do some thread safe work here
}

在这里使用Mutex的正确方法是哪种?

A)

void sharedFnc(){
  // do some thread safe work here
}
int main(){
 ...
 pthread_mutex_lock(&lock);
 sharedFnc();
 pthread_mutex_unlock(&lock);
 ...
}

或B)

void sharedFnc(){
  pthread_mutex_lock(&lock);
  // do some thread safe work here
  pthread_mutex_unlock(&lock);
}
int main(){
 ...
 sharedFnc();
 ...
}
iCMS 回答:是在共享函数内部还是外部使用互斥锁

让我们考虑两个极端:

在第一个极端中,直到进入函数内部,您甚至无法知道需要获取什么锁。也许函数找到了一个对象并对其进行了操作,而锁是针对每个对象的。那么呼叫者如何知道要持有什么锁?

也许代码需要在握住锁的同时做一些工作,而在不握住锁的情况下做一些工作。也许它需要在等待时释放锁。

在这种极端情况下,必须在函数内部获取并释放锁。

相反,该函数甚至可能根本不知道它被多个线程使用。它可能不知道其数据与什么锁相关联。也许是在不同的时间调用了不同的数据,并且数据受到了不同的锁保护。

也许它的调用者需要在保持相同锁的同时调用几个不同的函数。也许此函数报告了一些信息,线程将根据这些信息决定调用其他函数,并且至关重要的是,状态不能被这两个函数之间的另一个线程更改。

在这种极端情况下,呼叫者必须获取并释放锁。

在这两个极端之间,这是一个根据情况接近哪个极端进行的判断。而且,这些并不是唯一可用的两个选项。也有“中间”选项。

,

这种模式有话要说

// Only call this with `lock` locked.
//
static sometype foofunc_locked(...) {
    ...
}


sometype foofunc(...) {
    pthread_mutex_lock(&lock);
    sometype rVal = foofunc_locked(...);
    pthread_mutex_unlock(&lock);
    return rVal;
}

这将锁定和解锁互斥锁的职责foofunc_locked(...)体现的其他职责分开。

您要这样做的一个原因是,很容易看到foofunc()的所有可能的调用是否在lock返回之前将其解锁。如果将锁定和解锁与循环,switch语句,嵌套的if语句和returns从中间嵌套等等混合在一起,则可能不是这种情况。

,

如果锁位于函数内部,则最好确保该死的不涉及任何递归,尤其是没有间接递归。

函数内部的锁的另一个问题是循环,您有两个大问题:

  1. 性能。您释放并重新获得锁的每个周期。这可能会很昂贵,尤其是在Linux之类的操作系统(如关键部分)没有轻锁的情况下。

  2. 锁定语义。如果要在循环内部但在函数外部进行工作,则每个周期不能获取一次锁定,因为它将死锁您的函数。因此,您必须更多地分批处理循环周期,调用函数(acquire-release),然后手动获取锁,进行额外的工作,然后在周期结束之前手动释放它。而且,您绝对不能保证在释放函数和获取函数之间会发生什么。

本文链接:https://www.f2er.com/1689345.html

大家都在问