ما هو التنفيذ الأكثر كفاءة لمراقبة الكائنات مثل Java في C++؟

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

سؤال

في Java، يحتوي كل كائن على شاشة مزامنة.لذلك أعتقد أن التنفيذ مكثف جدًا من حيث استخدام الذاكرة ونأمل أن يكون سريعًا أيضًا.

عند نقل هذا إلى C++، ما هو أفضل تطبيق له.أعتقد أنه يجب أن يكون هناك شيء أفضل من "pthread_mutex_init" أم أن الكائن العلوي في Java مرتفع جدًا حقًا؟

يحرر:لقد تحققت للتو من أن حجم pthread_mutex_t على Linux i386 يبلغ 24 بايت.هذا ضخم إذا اضطررت إلى حجز هذه المساحة لكل كائن.

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

المحلول

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

نصائح أخرى

بمعنى أنه أسوأ من pthread_mutex_init, ، في الحقيقة.نظرًا لانتظار/إخطار Java، فأنت بحاجة إلى كائن مزامنة مقترن ومتغير شرط لتنفيذ شاشة.

من الناحية العملية، عند تنفيذ JVM، فإنك تتعقب وتطبق كل تحسين خاص بالمنصة في الكتاب، ثم تخترع بعض التحسينات الجديدة، لجعل الشاشات أسرع ما يمكن.إذا لم تتمكن من القيام بعمل شيطاني حقًا، فأنت بالتأكيد لست على مستوى تحسين جمع القمامة؛-)

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

من الناحية العملية، لا يقوم تطبيق Java العادي بالمزامنة على عدد كبير جدًا من الكائنات في وقت واحد، لذلك من المحتمل أن تكون مجموعات المراقبة بمثابة تحسين كبير في الوقت والذاكرة.

لست متأكدًا من كيفية قيام Java بذلك ، لكن .NET لا يحتفظ بالمواد التناظرية (أو التناظرية - الهيكل الذي يحمله يسمى "syncblk" هناك) مباشرة في الكائن. بدلاً من ذلك ، يحتوي على جدول عالمي من syncblks ، ويشير الكائنات إلى syncblk بواسطة الفهرس في هذا الجدول. علاوة على ذلك ، لا تحصل الكائنات على syncblk بمجرد إنشائها - بدلاً من ذلك ، تم إنشاؤها عند الطلب على القفل الأول.

أفترض (ملاحظة ، لا أعرف كيف يفعل ذلك بالفعل!) أنه يستخدم Atomic المقارنة والبوران لربط الكائن ومزامنته بطريقة آمنة مؤشر ترابط:

  1. تحقق من المخفي syncblk_index حقل كائننا لـ 0. إذا لم يكن 0 ، فقم بإغلاقه ومتابعة ، وإلا ...
  2. قم بإنشاء syncblk جديد في الجدول العالمي ، احصل على الفهرس لها (يتم الحصول على/إصدار الأقفال العالمية هنا حسب الحاجة).
  3. قارن وتبادل لكتابته في كائن نفسه.
  4. إذا كانت القيمة السابقة 0 (افترض أن 0 ليس فهرسًا صالحًا ، وهي القيمة الأولية لـ Hidden syncblk_index مجال كائناتنا) ، لم يتم التنافس على إنشاء syncblk. قفل عليها وتابع.
  5. إذا لم تكن القيمة السابقة 0 ، فإن شخصًا آخر قد أنشأ بالفعل syncblk وربطه بالكائن أثناء إنشاءنا له ، ولدينا فهرس هذا syncblk الآن. التخلص من الشخص الذي أنشأناه للتو ، وقفل على الشخص الذي حصلنا عليه.

وبالتالي فإن النفقات العامة لكل كائن هي 4 بايت (على افتراض مؤشرات 32 بت في جدول المزامنة) في أفضل حالات ، ولكن أكبر للكائنات التي تم قفلها بالفعل. إذا كنت نادراً ما تقفل الأشياء الخاصة بك ، فإن هذا المخطط يبدو وكأنه طريقة جيدة لخفض استخدام الموارد. ولكن إذا كنت بحاجة إلى قفل معظم أو جميع كائناتك في نهاية المطاف ، فقد يكون تخزين mutex مباشرة داخل الكائن أسرع.

بالتأكيد لا تحتاج إلى مثل هذا الشاشة كل هدف!

عند النقل من Java إلى C ++ ، فإنه يذهلني كفكرة سيئة لنسخ كل شيء بشكل أعمى. أفضل هيكل لـ Java ليس هو الأفضل لـ C ++ ، ليس أقلها لأن Java لديها مجموعة قمامة و C ++ لا.

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

سأستخدم مكتبة مؤشر ترابط Boost أو مكتبة مؤشر ترابط C ++ 0x الجديدة لإمكانية النقل بدلاً من الاعتماد على تفاصيل النظام الأساسي في كل منعطف. Boost.Thread يدعم Linux و MacOSX و Win32 و Solaris و HP-UX وغيرها. لي تنفيذ مكتبة مؤشر ترابط C ++ 0x حاليًا يدعم Windows و Linux فقط ، لكن التطبيقات الأخرى ستصبح متاحة في الوقت المناسب.

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