在同一线程中多次锁定互斥锁

发布于 2024-09-02 00:48:02 字数 930 浏览 3 评论 0原文

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

我有一个互斥锁和一个互斥锁,定义和初始化如下:

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 类型的互斥锁,但我也无法创建一个。

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

屌丝范 2024-09-09 00:48:02

这不是你所期望的吗?

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

从文档中可以看出:

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

也许您想要pthread_mutex_trylock?除非我们知道您想要实现什么目标,否则很难说。

更正:

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

思考后:

通过谷歌代码搜索,看起来 PTHREAD_MUTEX_RECURSIVE 并未在所有库中实现。您可以尝试 PTHREAD_MUTEX_RECURSIVE_NP,或者您可能做了一些奇特的事情来解决这个问题。

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.

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.

CORRECTION:

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

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.

深府石板幽径 2024-09-09 00:48:02

听起来 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
}

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:

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
}
欢你一世 2024-09-09 00:48:02

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

取自问题中的结论:

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

(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.
从﹋此江山别 2024-09-09 00:48:02

以下是在我的 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);

不要忘记在获取互斥体时多次释放它。

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

  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.

陈独秀 2024-09-09 00:48:02

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

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!

// 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文