سؤال

أقوم بتطوير تطبيق على نظام التشغيل Linux المضمن (Uclinux) وأحتاج إلى أن أكون قادرًا على قفل Mutex أكثر من مرة (بواسطة نفس الخيط).

لدي 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 لا تعمل ، لذلك لا يمكنني إنشاء mutex reentrant.
  • Try_lock ليس جيدًا أيضًا. يكتسب القفل إذا كان بإمكانه وإرجاع خطأ إذا لم يتمكن من الحصول على القفل. لسوء الحظ ، يخبرني الخطأ فقط أن Mutex قيد الاستخدام بالفعل ولا يمكنني معرفة ما إذا كان الخيط الحالي يمتلك بالفعل القفل أم لا.
  • يمكن لـ pthread_mutex_lock إرجاع خطأ إذا كان مؤشر الترابط الحالي يحتوي على القفل ولكنني بحاجة إلى إنشاء mutex من النوع pthread_mutex_errorcheck ، ولا يمكنني إنشاء واحد أيضًا.
هل كانت مفيدة؟

المحلول 5

(أدركت للتو أنني لم أميز هذا السؤال كما تم الإجابة عليه)

مأخوذة من الاستنتاجات في السؤال:

  • على ما يبدو pthread_mutex_recursive أو pthread_mutex_recursive_np لا تعمل ، لذلك لا يمكنني إنشاء mutex reentrant.
  • Try_lock ليس جيدًا أيضًا. يكتسب القفل إذا كان بإمكانه وإرجاع خطأ إذا لم يتمكن من الحصول على القفل. لسوء الحظ ، يخبرني الخطأ فقط أن Mutex قيد الاستخدام بالفعل ولا يمكنني معرفة ما إذا كان الخيط الحالي يمتلك بالفعل القفل أم لا.
  • يمكن لـ pthread_mutex_lock إرجاع خطأ إذا كان مؤشر الترابط الحالي يحتوي على القفل ولكنني بحاجة إلى إنشاء mutex من النوع pthread_mutex_errorcheck ، ولا يمكنني إنشاء واحد أيضًا.

نصائح أخرى

أليس هذا يفعل ما تتوقعه؟

تكتسب المكالمة الأولى القفل ، وسيتم حظر المكالمة الثانية حتى يتم إصدار القفل الأول (pthread_mutex_unlock). هذا ما تفعله الأقفال.

من الوثائق:

"إذا كان Mutex مغلقًا بالفعل ، فإن مؤشر ترابط الاتصال يحظر حتى يصبح Mutex متاحًا."

ربما تريد pthread_mutex_trylock؟ من الصعب القول ما لم نعرف ما تحاول إنجازه.

تصحيح:

لم أكن أرى أنك تقوم بتعيين pthread_mutex_recursive .... دعني أفكر في هذا الأمر أكثر من ذلك.

بعد التفكير:

من التثقيف حول Codesearch ، يبدو أن PTHREAD_MUTEX_RECURESIVE لم يتم تنفيذه في جميع libs. يمكنك تجربة pthread_mutex_recursive_np ، أو قد يكون لديك شيء يتوهم للتغلب على هذا.

يبدو أن pthread mutex لا يعيد إدخاله. يمكنك العمل حول هذا مع علامة تشير إلى ما إذا كان مؤشر الترابط الخاص بك قد أغلق 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
}

هنا يتم اختبار رمز العمل على 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. يمكنك القيام بأقفال متعددة على نفس الخيط على التوالي قبل الإلغاء دون القلق ، لكن تمانعك ، فهي ليست ممارسة مبرمج جيد. الطريقة الصحيحة هي استدعاء Lock () ، والسماح لمؤشر الترابط بتنفيذ القسم الحرج وإلغاء تأمين الاتصال () ، بحيث يمكن لخيوط أخرى تنفيذ نفس قطعة الكود بين القفل وفتح (يسمى ، القسم الحرج). يمنع الرمز أدناه حوادث أي مبرمج باستخدام سمات على 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