تجنب الجمود باستخدام واجهة العامة غير الافتراضية وراقب أقفال في C ++

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

سؤال

ولقد واجهت مشكلة التي تبدو مزعجة بالنسبة لي. يبدو أنني قد وجدت الوضع أن من السهل بما فيه الكفاية للعمل في جميع أنحاء، ولكن يمكن أن تؤدي إلى مشاكل إذا أ) لدي خلل في تركيز بينما البرمجة أو ب) شخص آخر يبدأ تنفيذ بلدي واجهات ولا يعرف كيفية التعامل مع هذا الوضع.

وهنا بلدي الإعداد الأساسي:

ولقد حصلت على فئة مجردة أنني وذلك باستخدام واجهة عامة لعدة أنواع البيانات. لقد اعتمدت غير ظاهري الواجهة العمومية نموذج (سوتر، 2001) جنبا إلى جنب مع راقب تأمين لتوفير بعض سلامة الموضوع. ومن شأن الطبقة سبيل المثال واجهة تبدو شيئا من هذا القبيل (لقد تركت التفاصيل حول تأمين راقب وتنفيذ مزامنة، وأنا لا أعتقد أنهم ذات الصلة):

class Foo
{
public:
    A( )
    {
        ScopedLock lock( mutex );
        aImp( );
    }
    B( )
    {
        ScopedLock lock( mutex );
        bImp( );
    }
protected:
    aImp( ) = 0;
    bImp( ) = 0;
}

ومن ثم يصل إلى المستخدم لتنفيذ AIMP وbImp، الذي هو المكان الذي يأتي المشكلة في حالة يؤدي AIMP بعض العمليات التي تستخدم bImp، فإنه من السهل للغاية (ومنطقي تقريبا، بمعنى ما) للقيام بذلك:

class Bar
{
protected:
    aImp( )
    {
        ...
        B( );
        ...
    }
    bImp( )
    {
        ...
    }
}

والجمود. بطبيعة الحال، فإن حل سهل لذلك هو دائما الاتصال وظائف افتراضية محمية بدلا من المتغيرات الخاصة به (استبدال B () مع bImp () في المقتطف أعلاه). لكنه لا يزال يبدو بعيدا لوسهلة لشنق نفسي إذا أخطأت، أو الأسوأ من ذلك السماح للآخرين لشنق أنفسهم.

هل لدى أي شخص بعض الطرق لمحاولة إما وقف المنفذ من فئة مجردة من استدعاء تلك المهام العامة على ترجمة لبعض الوقت، أو غير ذلك يساعد على تجنب حل المأزق؟

وفقط لركلات، بعض كائنات المزامنة تسمح للعملية التي ستساعد على تجنب المشاكل الجمود. وكمثال على ذلك، إذا كنت تنفيذ هذه باستخدام EnterCriticalSection النوافذ وظائف وLeaveCriticalSection، وليس هناك قضية. ولكن أنا أفضل أن تجنب منصة وظائف محددة. أنا حاليا باستخدام دفعة :: مزامنة وتعزيز :: shared_mutex في بلدي تنفيذ قفل راقب، وبقدر ما رأيته لا يحاول تجنب الجمود (والتي أعتقد أنني تقريبا تفضل ذلك).

هل كانت مفيدة؟

المحلول

وعن طريق الميراث الخاص من المحتمل أن يحل مشكلتك:

class Foo
{
public:
  void A( )
    {
      ScopedLock lock( mutex );
      aImp( );
    }
  void B( )
    {
      ScopedLock lock( mutex );
      bImp( );
    }

protected:
  virtual void aImp( ) = 0;
  virtual void bImp( ) = 0;
};

class FooMiddle : private Foo
{
public:
  using Foo::aImp;
  using Foo::bImp;
};

class Bar : public FooMiddle
{
  virtual void aImpl ()
  {
    bImp ();
    B ();                   // Compile error - B is private
  }
};

واشتقاق من فو القطاع الخاص، ومن ثم استخدام FooMiddle يضمن بار لا يستطيعون الوصول إلى A أو B. ومع ذلك، شريط لا يزال قادرا على تجاوز AIMP وbImp، والإعلانات استخدام في FooMiddle يعني أن هذه لا يزال من الممكن يسمى من بار.

وبدلا من ذلك، وهو الخيار الذي سوف <م> مساعدة ولكن لن يحل المشكلة هو استخدام نمط Pimpl. وكنت في نهاية المطاف مع شيء كما يلي:

class FooImpl
{
public:
  virtual void aImp( ) = 0;
  virtual void bImp( ) = 0;
};

class Foo
{
public:
  void A( )
    {
      ScopedLock lock( mutex );
      m_impl->aImp( );
    }
  void B( )
    {
      ScopedLock lock( mutex );
      m_impl->bImp( );
    }

private:
  FooImpl * m_impl;
}

وصالح هو أنه في الطبقات المستمدة من FooImpl، أنها لم يعد لدينا "فو" وجوه وهكذا لا يمكن الاتصال بسهولة "A" أو "B".

نصائح أخرى

ويجب أن لا يكون لديك مزامنة لمزامنة العودية. إذا ليس لها مزامنة العودية، ومحاولة ثانية لقفل لمزامنة في نفس موضوع يؤدي إلى أن حجب الموضوع. منذ أن موضوع تأمين مزامنة، ولكن يتم حظر على ذلك مزامنة، لديك طريق مسدود.

وربما كنت ترغب في النظر في:

boost::recursive_mutex

http://www.boost.org/doc /libs/1_32_0/doc/html/recursive_mutex.html

ومن المفترض أن تنفيذ العودية السلوك مزامنة عبر platform.Note Win32 وCRITICAL_SECTION ل(التي تستخدم عن طريق إدخال / LeaveCriticalSection) هي العودية، الذي من شأنه أن يخلق سلوك تصفون.

وحين قفل عودي من شأنه أن يحل مشكلتك، لقد شعرت دائما أنه في حين أن من الضروري في بعض الأحيان، في كثير من الحالات يتم استخدام قفل عودي وسيلة سهلة للخروج، وتأمين الطريق كثيرا.

ويتم تبسيط كود نشرت ديك الواضح لأغراض العرض التوضيحي، لذلك لست متأكدا إذا كان سوف تطبق.

وعلى سبيل المثال، دعنا نقول باستخدام الموارد X لا threadsafe. كنت قد حصلت على شيء من هذا القبيل.

A() {
   ScopedLock
   use(x)
   aImp()
   use(x)
}

aImp() {
   ScopedLock
   use(x)
}

ومن الواضح أن هذا من شأنه أن يؤدي إلى طريق مسدود.

<ع> استخدام الأقفال الخاصة بك أضيق بكثير ومع ذلك، فإن القضاء على هذه المشكلة. باستخدام الأقفال في نطاق صغير ممكن هو دائما فكرة جيدة، سواء لأسباب تتعلق بالأداء، وتجنب الجمود.

A() {
   {
      ScopedLock
      use(x)
   }
   aImp()
   {
      ScopedLock
      use(x)
   }
}

ويمكنك الحصول على هذه الفكرة.

وأنا على علم هذا ليس من الممكن دائما (أو من شأنه أن يؤدي إلى رمز innefficient فظيعة)، دون معرفة المزيد من التفاصيل وأنا لا أعرف ما إذا كان ينطبق على مشكلتك. ولكن يعتقد أنه كان يستحق نشر على أي حال.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top