C语言 在同一个线程中多次锁定互斥锁

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2821263/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:25:47  来源:igfitidea点击:

Lock a mutex multiple times in the same thread

clinuxposixembedded-linuxuclinux

提问by Megacan

I'm developing an application on an embedded linux OS (uClinux) and I need to be able to lock the mutex more than once (by the same thread).

我正在嵌入式 linux 操作系统 (uClinux) 上开发一个应用程序,我需要能够多次锁定互斥锁(通过同一线程)。

I have a mutex and a mutexattr defined and initialized as follows:

我定义并初始化了一个互斥锁和一个互斥锁,如下所示:

pthread_mutexattr_t waiting_barcode_mutexattr;
pthread_mutex_t waiting_barcode_mutex;

pthread_mutexattr_init(&waiting_barcode_mutexattr);
pthread_mutexattr_settype(&waiting_barcode_mutexattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&waiting_barcode_mutex, &waiting_barcode_mutexattr);

But when I try to acquire the lock twice it blocks on the second lock:

但是当我尝试两次获取锁时,它会在第二个锁上阻塞:

pthread_mutex_lock(&waiting_barcode_mutex);
pthread_mutex_lock(&waiting_barcode_mutex);

Am I initializing it wrong or is there a better way of accomplishing the same?

我初始化它是错误的还是有更好的方法来完成它?

Thanks in advance.

提前致谢。

Conclusions:

结论:

  • Apparently PTHREAD_MUTEX_RECURSIVE or PTHREAD_MUTEX_RECURSIVE_NP don't work so I can't create a reentrant mutex.
  • try_lock is no good either. It acquires the lock if it can and returns an error if it can't acquire the lock. Unfortunately the error just informs me that the mutex is already in use and I can′t find out if the current thread already owns the lock or not.
  • pthread_mutex_lock can return an error if the current thread has the lock but for that I need to create a mutex of the type PTHREAD_MUTEX_ERRORCHECK, and I can't create one either.
  • 显然 PTHREAD_MUTEX_RECURSIVE 或 PTHREAD_MUTEX_RECURSIVE_NP 不起作用,所以我无法创建可重入互斥锁。
  • try_lock 也不好。如果可以,它会获取锁,如果不能获取锁,则返回错误。不幸的是,错误只是告诉我互斥锁已在使用中,我无法确定当前线程是否已经拥有锁。
  • 如果当前线程有锁,pthread_mutex_lock 可以返回一个错误,但为此我需要创建一个 PTHREAD_MUTEX_ERRORCHECK 类型的互斥锁,我也不能创建一个。

采纳答案by Megacan

(Just realised I didn't mark this question as answered)

(刚刚意识到我没有将此问题标记为已回答)

Taken from the Conclusions in the question:

摘自问题中的结论:

  • Apparently PTHREAD_MUTEX_RECURSIVE or PTHREAD_MUTEX_RECURSIVE_NP don't work so I can't create a reentrant mutex.
  • try_lock is no good either. It acquires the lock if it can and returns an error if it can't acquire the lock. Unfortunately the error just informs me that the mutex is already in use and I can′t find out if the current thread already owns the lock or not.
  • pthread_mutex_lock can return an error if the current thread has the lock but for that I need to create a mutex of the type PTHREAD_MUTEX_ERRORCHECK, and I can't create one either.
  • 显然 PTHREAD_MUTEX_RECURSIVE 或 PTHREAD_MUTEX_RECURSIVE_NP 不起作用,所以我无法创建可重入互斥锁。
  • try_lock 也不好。如果可以,它会获取锁,如果不能获取锁,则返回错误。不幸的是,错误只是告诉我互斥锁已在使用中,我无法确定当前线程是否已经拥有锁。
  • 如果当前线程有锁,pthread_mutex_lock 可以返回一个错误,但为此我需要创建一个 PTHREAD_MUTEX_ERRORCHECK 类型的互斥锁,我也不能创建一个。

回答by Jeff B

Isn't this doing what you would expect?

这不是你所期望的吗?

The first call acquires the lock, and the second one will block until the first lock is released (pthread_mutex_unlock). This is what locks do.

第一个调用获取锁,第二个调用将阻塞,直到第一个锁被释放 ( pthread_mutex_unlock)。这就是锁的作用。

From the documentation:

从文档:

"If the mutex is already locked, the calling thread blocks until the mutex becomes available."

“如果互斥锁已被锁定,则调用线程会阻​​塞,直到互斥锁可用。”

Perhaps you want pthread_mutex_trylock? It's hard to say unless we know what you are trying to accomplish.

也许你想要pthread_mutex_trylock?除非我们知道你想要完成什么,否则很难说。

CORRECTION:

更正:

I didn't see that you were setting PTHREAD_MUTEX_RECURSIVE.... Let me think about this some more.

我没有看到你在设置 PTHREAD_MUTEX_RECURSIVE .... 让我再考虑一下。

AFTER THINKING:

深思熟虑后:

From poking around google codesearch, it looks like PTHREAD_MUTEX_RECURSIVE is not implemented in all libs. You may try PTHREAD_MUTEX_RECURSIVE_NP, or you may have do something fancy to get around this.

从 google codesearch 周围窥探,看起来 PTHREAD_MUTEX_RECURSIVE 并未在所有库中实现。你可以试试 PTHREAD_MUTEX_RECURSIVE_NP,或者你可能做了一些奇特的事情来解决这个问题。

回答by atk

It sounds like the pthread mutex is not reentrant. You could work around this with a flag indicating if your thread already has locked the mutex:

听起来 pthread 互斥锁不可重入。您可以使用一个标志来解决此问题,该标志指示您的线程是否已经锁定了互斥锁:

bool haveLock = false;// thread variable
pthread_mutex_t waiting_barcode_mutex; // also thread var

mylock()
{
   if( haveLock ) return; // no need to lock twice
   pthread_mutex_lock(&waiting_barcode_mutex);
   haveLock = true;
}

myunlock()
{
   haveLock = false;
   pthread_mutex_unlock(&waiting_barcode_mutex); // or whatever the unlock call is
}

回答by Sam

Here is working code tested on UBUNTU 12.04 LTS on my Dell m6300:

这是在我的 Dell m6300 上的 UBUNTU 12.04 LTS 上测试的工作代码:

  pthread_mutex_t mutex;
  pthread_mutexattr_t attr;
  int rc = pthread_mutexattr_init(&attr);
    if (rc != 0)
        throw (L"pthread_mutexattr_init returns " + rc);
    rc = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE_NP);
    if (rc != 0)
        throw (L"pthread_mutexattr_settype returns " + rc);
    rc = pthread_mutex_init (&mutex, &attr);
    if (rc != 0)
        throw (L"pthread_mutex_init returns " + rc);
    rc = pthread_mutexattr_destroy(&attr);
    if (rc != 0)
        throw (L"pthread_mutexattr_destroy returns " + rc);

   //first lock
   rc = pthread_mutex_lock(&mutex);
    if (rc != 0)
        throw (L"pthread_mutex_lock returns " + rc);
   //second lock
   rc = pthread_mutex_lock(&mutex);
    if (rc != 0)
        throw (L"pthread_mutex_lock returns " + rc);

Do not forget to release the mutex as many times as you acquired it.

不要忘记在获得互斥锁时多次释放它。

回答by Sammy

The code below shows that there is no problem in locking a critical section twice or thrice or N times before calling the unlock on pthread. You can do multiple locks on the same thread successively before unlocking without worrying but mind you, IT IS NOT a good programmer's practice. The right way is to call lock(), let the thread execute the critical section and call unlock(), so that other threads can execute the same piece of code between lock and unlock (called, critical section). The code below prevents any programmer's mishaps using ATTRIBUTES on pthread).

Read on!

下面的代码表明,在调用pthread 上的unlock 之前,将临界区锁定两次或三次或N 次是没有问题的。您可以在解锁之前在同一线程上连续执行多个锁定而不必担心,但请注意,这不是一个好的程序员实践。正确的方法是调用lock(),让线程执行临界区并调用unlock(),这样其他线程就可以执行lock和unlock之间的同一段代码(称为,临界区)。下面的代码可以防止任何程序员在 pthread 上使用 ATTRIBUTES 的失误)。

继续阅读!

// Example program using a thread locking multiple times sequentially before unlocking
#include <iostream>

using namespace std;

pthread_mutexattr_t     _attr;
pthread_mutex_t         _mutex;

///
/// Initialize mutex with error return locking mechanism (does not block
/// its own thread if multiple locks occurs.
///
void InitMutex()
{
   // Initialize mutex
   int ret=0;
   ret = pthread_mutexattr_settype(&_attr, PTHREAD_MUTEX_ERRORCHECK_NP);   // PTHREAD_MUTEX_ERRORCHECK_NP avoids double locking on same thread.
   if(ret != 0)
   {
      printf("Mutex attribute not initialized!!\n");
   }
   ret = pthread_mutex_init(&_mutex, &_attr);
   if(ret != 0)
   {
      printf("Mutex not initialized!!\n");
   }
}

///
/// Locks the critical section
///
int lock_me()
{
   return pthread_mutex_lock(&_mutex);
}

///
/// Unlocks the critical section
///
int unlock_me()
{
   return pthread_mutex_unlock(&_mutex);
}

int main()
{
  InitMutex(); // Very important
  int ret = 0;

  ret = lock_me();    // return value of 0 - OK
  cout << "First lock returns: "<< ret<< endl;
  ret = lock_me();    // returns a value like 35 - ERROR, but ignores locking again
  cout << "Second lock returns: "<< ret<< endl;

  // Do something in this critical section. No other thread can execute this at this time before unlock. Other threads (if any) wait at lock() waiting for main function to unlock() first.

  ret = unlock_me();  // unlocks the critical section. All is OK
  cout << "First unlock returns: "<< ret<< endl;
  ret = unlock_me();  // returns error value of 1, nothing to lock
  cout << "Second unlock returns: "<< ret<< endl;
  ret = unlock_me();  // same as above, nothing to do. Ignore and move on!
  cout << "Third unlock returns: "<< ret << endl;

  // The main() thread will never have a race condition ;) All iz well!!

  pthread_mutexattr_destroy(&_attr);    // clean up the mutex attribute
  pthread_mutex_destroy(&_mutex);       // clean up the mutex itself

}

OUTPUT:

输出:

First lock returns: 0

Second lock returns: 35

First unlock returns: 0

Second unlock returns: 1

Third unlock returns: 1

第一个锁返回:0

第二个锁返回:35

第一次解锁返回:0

第二次解锁返回:1

第三次解锁返回:1