سؤال

سؤال أساسي إلى حد ما، لكنني لا أرى أنه تم طرحه في أي مكان.

لنفترض أن لدينا بنية عالمية (في لغة C) مثل:

struct foo {
  int written_frequently1;
  int read_only;
  int written_frequently2;
};

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

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

(أنا أميل إلى قول لا، لأن حقيقة أن المواقع قبل وبعد التغيير المستمر لا ينبغي أن تؤثر على read_only عضو، ويجب ألا تتداخل سلاسل الرسائل المتعددة التي تقرأ القيمة مع بعضها البعض.ولكني لست متأكدا.)


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

struct bar {
  char written_frequently1[LONGISH_LEN];
  char read_only[LONGISH_LEN];
  char written_frequently2[LONGISH_LEN];
};

القضية الرئيسية التي سألت عنها هي، بما أن هذه البيانات جزء من البنية، فهل تتأثر على الإطلاق بأعضاء البنية الآخرين، وهل يمكن أن تؤثر عليهم في المقابل؟

حقيقة أن الأعضاء كانوا من الباحثين، وبالتالي من المحتمل أن تكون الكتابة ذرية، هي في الحقيقة مجرد ذريعة حمراء في هذه الحالة.]

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

المحلول 10

وشكرا جزيلا لجميع answerers كبيرة (ولجميع الإجابات كبيرة).

لتلخيص:

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

وهذا صحيح حتى لو تمت كتابتها الأعضاء الآخرين في كثير من الأحيان. حقيقة أن المتغيرات المختلفة كلها جزء من نفس البنية لا فرق.

نصائح أخرى

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

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


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

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

إذا فعلا قراءة عضو READ_ONLY فقط، ثم لا يوجد أي خطر من البيانات يتم تغييرها، وبالتالي لا حاجة لإجراء التزامن. هذا يمكن أن يكون وبدأت البيانات التي تم إعدادها من قبل الخيوط.

وأنت تريد مزامنة أي البيانات التي يمكن أن تكون مكتوبة، بغض النظر عن التردد.

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

يحتاج القراء إلى كائنات المزامنة أيضًا!

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

وإليك السبب، في شكل مثال.

تخيل ساعة يتم تحديثها كل ثانية بالرمز:

if (++seconds > 59) {        // Was the time hh:mm:59?
   seconds = 0;              // Wrap seconds..
   if (++minutes > 59)  {    // ..and increment minutes.  Was it hh:59:59?
     minutes = 0;            // Wrap minutes..
     if (++hours > 23)       // ..and increment hours.  Was it 23:59:59?
        hours = 0;           // Wrap hours.
    }
}

إذا لم يكن الكود محميًا بواسطة كائن المزامنة (mutex)، فيمكن لخيط آخر قراءة ملف hours, minutes, ، و seconds المتغيرات أثناء التحديث قيد التقدم.باتباع الكود أعلاه:

[Start just before midnight] 23:59:59
[WRITER increments seconds]  23:59:60
[WRITER wraps seconds]       23:59:00
[WRITER increments minutes]  23:60:00
[WRITER wraps minutes]       23:00:00
[WRITER increments hours]    24:00:00
[WRITER wraps hours]         00:00:00

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

الإصلاح بسيط.

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

لا.

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

وكيف حالك وضع read_only في البداية؟

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

وأنت قد تتمتع قراءة أي واحدة من هذه الأوراق على قفل العملي البرمجة المجانية أو مجرد تشريح وفهم قصاصات المقدمة.

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

إضافة إلى الإجابات السابقة:

  1. في هذه الحالة، نموذج التزامن الطبيعي هو الاستبعاد المتبادل، وليس الإشارات.
  2. أوافق على أنك لا تحتاج إلى أي كائن المزامنة (mutex) على المتغيرات للقراءة فقط.
  3. إذا كان جزء القراءة والكتابة من الهيكل به قيود على الاتساق، فستحتاج بشكل عام واحد كائن المزامنة لـ الجميع منهم، من أجل الحفاظ على العمليات الذرية.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top