سؤال

ما هي التوترات بين مؤشرات الترابط المتعددة وسلامة الاستثناءات في C++؟هل هناك إرشادات جيدة يجب اتباعها؟هل يتم إنهاء مؤشر الترابط بسبب استثناء لم يتم اكتشافه؟

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

المحلول

وأعتقد أن مستوى C ++ لا تجعل أي ذكر لخاصية تعدد - خاصية تعدد هو سمة من سمات الخاصة بالنظام الأساسي

.

ولست متأكدا بالضبط ما يقوله مستوى C ++ حول الاستثناءات uncaught بشكل عام، ولكن وفقا ل<لأ href = "http://www.devx.com/tips/Tip/14240" يختلط = "نوفولو noreferrer" > هذه الصفحة ، ما يحدث هو تعريف نظام أساسي، ويجب عليك معرفة في وثائق المجمع الخاص بك.

في اختبار سريع وقذرة فعلت مع g ++ 4.0.1 (i686-التفاح-darwin8-ز ++ - 4.0.1 أن تكون محددة)، والنتيجة هي أن terminate() يسمى، الذي يقتل البرنامج بأكمله. رمز اعتدت يلي:

#include <stdio.h>
#include <pthread.h>

void *threadproc(void *x)
{
  throw 0;

  return NULL;
}

int main(int argc, char **argv)
{
  pthread_t t;
  pthread_create(&t, NULL, threadproc, NULL);

  void *ret;
  pthread_join(t, &ret);

  printf("ret = 0x%08x\n", ret);

  return 0;
}

وجمعت مع g++ threadtest.cc -lpthread -o threadtest. الناتج هو:

terminate called after throwing an instance of 'int'

نصائح أخرى

وC ++ 0X سيكون اللغة دعم لنقل الاستثناءات بين المواضيع حتى أنه عندما يلقي ترابط استثناء في موضوع التفريخ يمكن التقاط أو rethrow ذلك.

ومن الاقتراح:

namespace std {

    typedef unspecified exception_ptr;

    exception_ptr current_exception();
    void rethrow_exception( exception_ptr p );

    template< class E > exception_ptr copy_exception( E e );
}

واستثناء uncaught سيدعو terminate() وهذا بدوره يدعو terminate_handler (التي يمكن وضعها من قبل البرنامج). افتراضيا يدعو terminate_handler abort().

وحتى لو كنت تجاوز terminate_handler الافتراضي، يقول المعيار الذي الروتين التي تقدمها "يجب إنهاء تنفيذ البرنامج دون العودة إلى المستدعي" (ISO 14882-2003 18.6.1.3).

وهكذا، وباختصار، استثناء uncaught ستنتهي البرنامج ليس فقط موضوع.

وبقدر ما يذهب سلامة موضوع، كما يقول آدم روزنفيلد ، وهذا شيء معين منصة وهذا ما لم يتم التصدي لها من قبل المعيار.

وهذا هو سبب واحد أكبر أن إرلانج موجودا.

وأنا لا أعرف ما هي الاتفاقية، ولكن إيمهو، تكون إرلانج مثل ممكن. جعل كومة الكائنات غير قابل للتغيير واقامة نوع من بروتوكول تمرير رسالة للاتصال بين المواضيع. تجنب الأقفال. تأكد وفاة الرسالة، باستثناء آمن. حافظ على الكثير من الاشياء جليل على المكدس.

وكما ناقشنا الآخرين، التزامن (وموضوع السلامة على وجه الخصوص،) هي قضية المعمارية، والتي تؤثر على كيفية تقوم بتصميم النظام الخاص بك وطلبك.

ولكن أود أن تأخذ سؤالك حول التوتر بين استثناء السلامة وموضوع السلامة.

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

class Foo {
public:
  void set_value(std::string const & s);

  std::string const & value() const;
};

إذا هو مشترك فو من المواضيع متعددة، صعوبة في انتظاركم. وبطبيعة الحال، هل يمكن وضع مزامنة أو غيرها من القفل للوصول فو. ولكن سرعان ما يكفي، جميع المبرمجين C ++ يريد أن التفاف فو الى "ThreadSafeFoo". بلدي الخلاف، غير أن واجهة لفو ينبغي تغييرها إلى:

class Foo {
public:
  void set_value(std::string const & s);

  std::string value() const;
};

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

أحد الأمثلة الكلاسيكية (لا أتذكر أين رأيته لأول مرة) موجود في مكتبة الأمراض المنقولة جنسياً.

إليك كيفية إخراج شيء ما من قائمة الانتظار:

T t;
t = q.front(); // may throw
q.pop();

هذه الواجهة منفرجة إلى حد ما مقارنة بـ:

T t = q.pop();

ولكن يتم ذلك لأن مهمة نسخة T يمكن أن ترمي.إذا ظهرت النسخة بعد حدوث النافذة، فسيتم فقدان هذا العنصر من قائمة الانتظار، ولا يمكن استعادته أبدًا.ولكن بما أن النسخة تحدث قبل ظهور العنصر، فيمكنك وضع معالجة عشوائية حول النسخة من front() في كتل المحاولة/التقاط.

العيب هو أنه لا يمكنك تنفيذ قائمة انتظار آمنة لمؤشر الترابط باستخدام واجهة std::queue بسبب الخطوتين المتضمنتين.ما هو جيد بالنسبة لسلامة الاستثناء (فصل الخطوات التي يمكن أن ترمي)، أصبح الآن سيئًا بالنسبة لتعدد العمليات.

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

هناك مشكلتان لاحظتهما:

  • في g++ على Linux، يتم قتل مؤشر الترابط (pthread_cancel) عن طريق طرح استثناء "غير معروف".من ناحية، يتيح لك ذلك التنظيف بشكل جيد عندما يتم قتل الخيط.من ناحية أخرى، إذا لاحظت هذا الاستثناء ولم تقم بإعادة طرحه، فسينتهي الكود الخاص بك بـ abort().لذلك، إذا قمت أنت أو أي من المكتبات التي تستخدمها بقتل سلاسل الرسائل، فلا يمكنك الحصول عليها

    يمسك(...)

بدون

throw;

في التعليمات البرمجية الخيوط الخاصة بك. هنا هو إشارة إلى هذا السلوك على شبكة الإنترنت:

  • في بعض الأحيان تحتاج إلى نقل الاستثناء بين المواضيع.هذا ليس بالأمر السهل - فقد انتهى بنا الأمر إلى القيام ببعض الاختراقات، عندما يكون الحل المناسب هو نوع التنظيم/التنظيم الذي ستستخدمه بين العمليات.

وأنا لا أنصح السماح لأي استثناء تبقى uncaught. التفاف وظائف موضوع المستوى الأعلى في التقاط كل معالجات التي يمكن أن برشاقة (أو على الأقل verbosely) اغلاق البرنامج.

وأعتقد أن الشيء الأكثر أهمية هو أن نتذكر أن الاستثناءات uncaught من المواضيع الأخرى لا تظهر للمستخدم أو ألقيت في موضوع الرئيسي. ولذلك عليك أن تشوه كافة التعليمات البرمجية التي يجب تشغيلها على المواضيع المختلفة من الترابط الرئيسي مع كتل حاول / catch.

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