Pergunta

Estou desenvolvendo um aplicativo em um sistema operacional Linux incorporado (UCLinux) e preciso ser capaz de bloquear o mutex mais de uma vez (pelo mesmo thread).

Eu tenho um mutex e um mutexattr definido e inicializado da seguinte forma:

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

Mas quando tento adquirir a fechadura duas vezes, ele bloqueia na segunda trava:

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

Estou inicializando errado ou existe uma maneira melhor de realizar o mesmo?

Desde já, obrigado.

Conclusões:

  • Aparentemente, pthread_mutex_recursive ou pthread_mutex_recursive_np não funcionam, então não posso criar um mutex reentrante.
  • Try_lock também não é bom. Ele adquire o bloqueio, se puder e retorna um erro se não puder adquirir o bloqueio. Infelizmente, o erro apenas me informa que o mutex já está em uso e não consigo descobrir se o thread atual já possui o bloqueio ou não.
  • pthread_mutex_lock pode retornar um erro se o encadeamento atual tiver o bloqueio, mas para isso eu preciso criar um mutex do tipo pthread_mutex_errorcheck e também não posso criar um.
Foi útil?

Solução 5

(Acabei de perceber que não marquei essa pergunta como respondido)

Tirado das conclusões da pergunta:

  • Aparentemente, pthread_mutex_recursive ou pthread_mutex_recursive_np não funcionam, então não posso criar um mutex reentrante.
  • Try_lock também não é bom. Ele adquire o bloqueio, se puder e retorna um erro se não puder adquirir o bloqueio. Infelizmente, o erro apenas me informa que o mutex já está em uso e não consigo descobrir se o thread atual já possui o bloqueio ou não.
  • pthread_mutex_lock pode retornar um erro se o encadeamento atual tiver o bloqueio, mas para isso eu preciso criar um mutex do tipo pthread_mutex_errorcheck e também não posso criar um.

Outras dicas

Isso não está fazendo o que você esperaria?

A primeira chamada adquire a fechadura, e a segunda bloqueará até que a primeira trava seja liberada (pthread_mutex_unlock). É isso que os bloqueios fazem.

Da documentação:

"Se o mutex já estiver bloqueado, o encadeamento de chamadas blocos até que o mutex fique disponível".

Talvez você queira pthread_mutex_trylock? É difícil dizer, a menos que saibamos o que você está tentando realizar.

CORREÇÃO:

Não vi que você estava definindo pthread_mutex_recursive .... deixe -me pensar um pouco mais.

Depois de pensar:

De cutucar o Google Codesearch, parece que Pthread_mutex_recursive não é implementado em todas as libs. Você pode experimentar pthread_mutex_recursive_np, ou pode ter feito algo sofisticado para contornar isso.

Parece que o pThread Mutex não é reentrante. Você pode contornar isso com uma bandeira indicando se seu tópico já bloqueou o 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
}

Aqui está o código de trabalho testado no Ubuntu 12.04 LTS no meu 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);

Não se esqueça de liberar o Mutex quantas vezes você o adquiriu.

O código abaixo mostra que não há problema em travar uma seção crítica duas ou três vezes ou n vezes antes de ligar para o desbloqueio no pThread. Você pode fazer vários bloqueios no mesmo segmento sucessivamente antes de desbloquear sem se preocupar, mas lembre -se, não é uma boa prática de um programador. A maneira correta é chamar o bloqueio (), que o encadeamento execute a seção crítica e a chamada desbloqueio (), para que outros threads possam executar a mesma peça de código entre o bloqueio e o desbloqueio (chamado, seção crítica). O código abaixo impede os contratempos de qualquer programador usando atributos no pThread).

Leia!

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

}

RESULTADO:

First Lock Returns: 0

Segundo Lock Returns: 35

Primeiro desbloqueio retorno: 0

Segundo desbloqueio retorno: 1

Terceiro desbloqueio retorno: 1

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top