Domanda

Sto sviluppando un'applicazione su un sistema operativo Linux incorporato (UCLINUX) e devo essere in grado di bloccare il mutex più di una volta (con lo stesso thread).

Ho un mutex e un mutexattr definito e inizializzato come segue:

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

Ma quando provo ad acquisire la serratura due volte, si blocca sul secondo blocco:

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

Lo sto iniziando male o c'è un modo migliore per realizzare lo stesso?

Grazie in anticipo.

Conclusioni:

  • Apparentemente pThread_mutex_recursive o pThread_mutex_recursive_np Non funzionare, quindi non posso creare un mutex rientrante.
  • try_lock non va bene neanche. Acquisisce il blocco se può e restituisce un errore se non è possibile acquisire il blocco. Sfortunatamente l'errore mi informa solo che il mutex è già in uso e non riesco a scoprire se il thread corrente possiede già il blocco o meno.
  • pThread_mutex_lock può restituire un errore se il thread corrente ha il blocco ma per questo ho bisogno di creare un mutex del tipo pThread_mutex_errorcheck e neanche io non posso crearne uno.
È stato utile?

Soluzione 5

(Mi sono appena reso conto di non aver segnato questa domanda come risposta)

Tratto dalle conclusioni della domanda:

  • Apparentemente pThread_mutex_recursive o pThread_mutex_recursive_np Non funzionare, quindi non posso creare un mutex rientrante.
  • try_lock non va bene neanche. Acquisisce il blocco se può e restituisce un errore se non è possibile acquisire il blocco. Sfortunatamente l'errore mi informa solo che il mutex è già in uso e non riesco a scoprire se il thread corrente possiede già il blocco o meno.
  • pThread_mutex_lock può restituire un errore se il thread corrente ha il blocco ma per questo ho bisogno di creare un mutex del tipo pThread_mutex_errorcheck e neanche io non posso crearne uno.

Altri suggerimenti

Non sta facendo quello che ti aspetteresti?

La prima chiamata acquisisce il blocco e la seconda bloccherà fino al rilascio del primo blocco (pthread_mutex_unlock). Questo è ciò che fanno le serrature.

Dalla documentazione:

"Se il mutex è già bloccato, il thread chiamante blocca fino a quando il mutex diventa disponibile."

Forse vuoi pthread_mutex_trylock? È difficile da dire a meno che non sappiamo cosa stai cercando di realizzare.

CORREZIONE:

Non ho visto che stavi impostando pThread_mutex_recursive .... fammi pensare ancora a questo.

Dopo aver pensato:

Dall'affrontare Google Codesearch, sembra che pThread_mutex_recursive non sia implementato in tutti i libri. Puoi provare pThread_mutex_recursive_np, oppure potresti aver fatto qualcosa di strano per aggirare questo.

Sembra che Pthread Mutex non sia rientrante. Potresti aggirare questo con un flag che indica se il tuo thread ha già bloccato il 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
}

Ecco il codice di lavoro testato su Ubuntu 12.04 LTS sul mio 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);

Non dimenticare di rilasciare il Mutex tutte le volte che l'hai acquisito.

Il codice seguente mostra che non vi è alcun problema nel bloccare una sezione critica due volte o tre volte o n prima di chiamare lo sblocco su PThread. Puoi fare più serrature sullo stesso thread in successione prima di sbloccare senza preoccuparti, ma intendiamoci, non è una buona pratica del programmatore. Il modo giusto è chiamare Lock (), lasciare che il thread esegui la sezione critica e chiama un blocco (), in modo che altri thread possano eseguire lo stesso pezzo di codice tra blocco e sblocco (chiamato, sezione critica). Il codice seguente impedisce gli incidenti di qualsiasi programmatore utilizzando gli attributi su PThread).

Continuare a leggere!

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

}

PRODUZIONE:

Primo blocco ritorna: 0

Ritorni del secondo blocco: 35

Primo Sblocco Restituisce: 0

Secondo sblocco Restituisce: 1

Terzo Unlock Returns: 1

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top