Заблокируйте мьютекс несколько раз в одном и том же потоке

StackOverflow https://stackoverflow.com/questions/2821263

Вопрос

Я разрабатываю приложение на встроенной ОС Linux (uClinux), и мне нужно иметь возможность блокировать мьютекс более одного раза (одним и тем же потоком).

У меня есть мьютекс и 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, и я тоже не могу его создать.
Это было полезно?

Решение 5

(Только что понял, что я не отметил этот вопрос, как ответ)

Взяты из выводов в вопросе:

  • Видимо pthread_mutex_recursive или pthread_mutex_recursive_np не работают, поэтому я не могу создать reentrant mutex.
  • try_lock тоже не хорошо. Он получает блокировку, если он может и возвращает ошибку, если она не может получить блокировку. К сожалению, ошибка просто сообщает мне, что MUTEX уже используется, и я не могу узнать, если текущий поток уже принадлежит блокировку или нет.
  • pthread_mutex_lock может вернуть ошибку, если текущий поток имеет замок, но для этого мне нужно создать mutex типа pthread_mutex_errorcheck, и я тоже не могу создать.

Другие советы

Разве это не делает то, что вы ожидаете?

Первый вызов приобретает блокировку, а второй заблокирует, пока не будет выделен первый замок (pthread_mutex_unlock). Это то, что делают замки.

Из документации:

«Если METEX уже заблокирован, вызывающие блок поток до тех пор, пока Mutex не станет доступным».

Возможно, вы хотите pthread_mutex_trylock? Трудно сказать, если мы не знаем, что вы пытаетесь сделать.

Коррекция:

Я не видел, что вы установили Pthread_mutex_recursive .... Позвольте мне подумать об этом еще немного.

После мышления:

Из коды Google CodeSearch он выглядит как pthread_mutex_recursive не реализуется во всех libs. Вы можете попробовать pthread_mutex_recursive_np, или вы, возможно, сделали что-то фантастическое, чтобы обойти это.

Похоже, что мьютекс 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
}

Вот рабочий код протестирован на Ubuntu 12.04 LTS на моем 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);

Не забудьте отпустить Mutex столько раз, сколько вы приобрели.

Ниже приведен код, показывает, что нет проблем в блокировке критического раздела дважды или трижды или N раз перед вызовом разблокировки на Pthread. Вы можете сделать несколько замков на одной и той же ниве последовательно перед разблокировкой, не беспокоясь, но не ума, это не хорошая практика программиста. Правильный способ состоит в том, чтобы позвонить заблокировать (), пусть поток выполняется критический раздел и вызов разблокировки (), чтобы другие потоки могли выполнить один и тот же кусок кода между блокировкой и разблокировкой (называемый критическими сечением). Код ниже предотвращает Mishaps любых программистов, используя атрибуты на Pthread).

Читать дальше!

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top