2013-06-03 32 views
11

我用pthread编写了一个使用生产者 - 消费者模型的多线程程序。Pthread互斥锁:pthread_mutex_unlock()消耗大量时间

当我使用英特尔VTune分析器来分析我的程序时,我发现生产者和消费者花费大量时间在pthread_mutex_unlock上。我不明白为什么会发生这种情况。我认为线程可能会等待很长时间才能获得互斥锁,但释放互斥锁应该很快,对吧?

以下快照来自Intel VTune。它显示了消费者试图从缓冲区获取项目的代码,以及每个代码行消耗的时间。

我的问题是,为什么pthread_mutex_unlock有这样的开销? pthread互斥体本身的问题还是与我使用它的方式有关? enter image description here

+0

如果互斥体上存在大量争用,则解锁互斥体可能会很慢,因为部分解锁工作正在唤醒等待互斥体的任何线程。 – caf

+6

我认为如果将'pthread_mutex_unlock()'调用移动到'pthread_cond_signal()'的调用上方,将会看到结果会很有趣。没有要求在发信号通知条件变量时(仅在等待它时)持有互斥体,并且我怀疑发生了什么事情是信号引起互斥体的争用,因为立即释放的线程会尝试获取互斥体,信令线程仍然成立。 –

+2

@MichaelBurr好点!我测试了你的建议,现在这个程序快了大约40%。 –

回答

2

pthread_mutex_unlock()函数将释放由互斥量引用的互斥对象。但是,释放互斥体的方式取决于互斥体的类型属性。如果调用pthread_mutex_unlock()时互斥体引用的互斥体对象上存在线程阻塞,导致互斥体变为可用,则调度策略应确定哪个线程将获取互斥体。

如果互斥体类型为PTHREAD_MUTEX_NORMAL,则不应提供死锁检测。试图重新锁定互斥锁会导致死锁。如果线程试图解锁未锁定的互斥锁或解锁的互斥锁,则会导致未定义的行为。

如果互斥类型为PTHREAD_MUTEX_ERRORCHECK,则应提供错误检查。如果线程试图重新锁定已锁定的互斥锁,则应返回错误。如果线程试图解锁未锁定的互斥锁或已解锁的互斥锁,则应返回错误。

如果互斥体类型为PTHREAD_MUTEX_RECURSIVE,那么互斥体应保持锁定计数的概念。当线程第一次成功获取互斥锁时,锁定计数应设置为1。每次线程重新锁定此互斥锁时,锁定计数应递增1。每次线程解锁互斥锁时,锁定计数应减1。当锁计数达到零时,互斥量将可供其他线程获取。如果线程试图解锁未锁定的互斥锁或已解锁的互斥锁,则应返回错误。

如果互斥体类型为PTHREAD_MUTEX_DEFAULT,则尝试递归锁定互斥体会导致未定义的行为。如果未被调用线程锁定,则试图解锁互斥锁会导致未定义的行为。尝试解锁互斥锁,如果未锁定,则会导致未定义的行为。

我通常更喜欢使用PTHREAD_MUTEX_RECURSIVE互斥量,因为在这种情况下,互斥量在计数达到零时可用,并且调用线程不再在此互斥锁上有任何锁定。