【问题标题】:Lock a mutex multiple times in the same thread在同一个线程中多次锁定互斥锁
【发布时间】:2010-05-12 17:34:17
【问题描述】:

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

我有一个 mutex 和一个 mutexattr 定义和初始化如下:

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

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

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

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

提前致谢。

结论:

  • 显然 PTHREAD_MUTEX_RECURSIVE 或 PTHREAD_MUTEX_RECURSIVE_NP 不起作用,因此我无法创建可重入互斥体。
  • try_lock 也不好。如果可以,它会获取锁,如果无法获取锁,则返回错误。不幸的是,错误只是告诉我互斥锁已在使用中,我无法确定当前线程是否已经拥有锁。
  • 如果当前线程有锁,pthread_mutex_lock 会返回错误,但为此我需要创建一个 PTHREAD_MUTEX_ERRORCHECK 类型的互斥锁,我也无法创建。

【问题讨论】:

  • 你为什么要多次锁定它?通常使用互斥锁,以便在任何给定时间只有一部分代码可以拥有锁。
  • 基本上它与我设置代码和辅助功能的方式有关。也许我应该更改我的代码并避免这种情况。无论如何,我很好奇。
  • 您是否正在检查属性和互斥初始化调用的返回值?可能是你的 libc 不支持递归锁?
  • @Nikolai:我忘了测试返回值,但我现在测试了它们,它们都返回 0。@Brian:不,我不想使用信号量。

标签: c linux posix embedded-linux uclinux


【解决方案1】:

这不符合你的预期吗?

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

来自文档:

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

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

更正:

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

经过思考:

从谷歌代码搜索中发现,似乎 PTHREAD_MUTEX_RECURSIVE 并未在所有库中实现。您可以尝试 PTHREAD_MUTEX_RECURSIVE_NP,或者您可能已经做了一些花哨的事情来解决这个问题。

【讨论】:

  • 我想我必须使用trylock。过去两年我一直在.Net 中编程,我假设锁默认是可重入的。好久没用 C 编程了。
【解决方案2】:

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

bool haveLock = false;// 线程变量 pthread_mutex_t waiting_barcode_mutex; // 也是线程变量 我的锁() { 如果(有锁)返回; // 不需要锁定两次 pthread_mutex_lock(&waiting_barcode_mutex); 有锁=真; } 我的解锁() { 有锁=假; pthread_mutex_unlock(&waiting_barcode_mutex); // 或者无论解锁调用是什么 }

【讨论】:

    【解决方案3】:

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

    取自问题中的结论:

    • 显然 PTHREAD_MUTEX_RECURSIVE 或 PTHREAD_MUTEX_RECURSIVE_NP 不起作用,因此我无法创建可重入互斥体。
    • try_lock 也不好。如果可以,它会获取锁,如果无法获取锁,则返回错误。不幸的是,错误只是告诉我互斥锁已在使用中,我无法确定当前线程是否已经拥有锁。
    • 如果当前线程有锁,pthread_mutex_lock 会返回错误,但为此我需要创建一个 PTHREAD_MUTEX_ERRORCHECK 类型的互斥锁,我也无法创建。

    【讨论】:

      【解决方案4】:

      这是在我的戴尔 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);
      

      不要忘记释放互斥锁的次数与获得它的次数一样多。

      【讨论】:

        【解决方案5】:

        下面的代码表明,在 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
        
        }
        

        输出:

        第一个锁返回:0

        第二次锁定返回:35

        第一次解锁返回:0

        第二次解锁返回:1

        第三次解锁返回:1

        【讨论】:

        • 您是否阅读了问题的一部分:“如果当前线程有锁,pthread_mutex_lock 可以返回错误,但为此我需要创建 PTHREAD_MUTEX_ERRORCHECK 类型的互斥锁,但我不能也创建一个。”?
        猜你喜欢
        • 2021-02-19
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 2012-12-25
        • 1970-01-01
        • 2014-05-02
        相关资源
        最近更新 更多