سؤال

أفهم الوظيفة الرئيسية لكلمة القفل الرئيسية من MSDN

بيان القفل (مرجع C#)

تمثل الكلمة الرئيسية القفل كتلة بيان كقسم مهم من خلال الحصول على قفل الاستثمار المتبادل لكائن معين ، وتنفيذ عبارة ، ثم إطلاق القفل.

متى يجب استخدام القفل؟

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

هل هناك مشاكل في الأداء عند استخدام القفل؟

لقد ورثت للتو تطبيقًا يستخدم القفل في كل مكان، وهو ذو خيط واحد وأريد أن أعرف هل يجب أن أتركه، هل هو ضروري أصلاً؟

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

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

المحلول

متى يجب استخدام القفل؟

يجب استخدام القفل لحماية الموارد المشتركة في التعليمات البرمجية متعددة الخيوط.ليس من أجل أي شيء آخر.

ولكن هل يكون ذلك ضروريًا عندما لا يقوم التطبيق بفصل أي سلاسل رسائل أخرى؟

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

هل هناك مشاكل في الأداء عند استخدام القفل؟

نعم.إنها ليست كبيرة جدًا في تطبيق واحد، ولكن لماذا تجري مكالمات لا تحتاج إليها؟

...إذا كان هذا هو نمط التصميم الجيد الذي يجب اتباعه في المستقبل[?]

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

نصائح أخرى

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

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

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

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

لمزيد من المعلومات، اقرأ هذه المقالة عن مخاطر Thread.Abort().

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

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

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

القفل هو في الواقع مُسلسل للوصول إلى الذاكرة، وستنتظر الخيوط (التي تأخذ القفل) على القفل للدخول حتى يخرج الخيط الحالي من القفل، لذلك يتم تسلسل الوصول إلى الذاكرة.

للإجابة على سؤالك، ليست هناك حاجة إلى قفل الأسئلة في تطبيق مترابطة واحد، وله آثار جانبية على الأداء.لأن الأقفال في C# تعتمد على كائنات مزامنة kernel وكل قفل تقوم به ينشئ انتقالًا إلى وضع kernel من وضع المستخدم.

إذا كنت مهتمًا بأداء مؤشرات الترابط المتعددة، فالمكان الجيد للبدء هو إرشادات خيوط MSDN

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

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

نعم، سيكون هناك بعض العقوبات على الأداء عند استخدام القفل، لكنها بشكل عام لا تذكر بما يكفي لعدم الاهتمام.

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

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

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

انظر سؤال حول "Mutex" في C#.ومن ثم انظر هؤلاء اثنين أسئلة بخصوص استخدام عبارة "lock(Object)" على وجه التحديد.

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

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