C #: ما هو الفرق بين مؤشر الترابط الآمن والذري؟


الاجابه 1:

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

لتطبيق الأقفال ، لديك خياران:

  1. احصل على دعم الأجهزة للعمليات الذرية - إرشادات مركبة خاصة تنفذ ككل ، مثل Test-and-set.Be ذكية (وتعاني من العواقب) - خوارزمية Peterson.

في المثال الخاص بك في التفاصيل ، كلاهما غير آمن. إذا فهمت بشكل صحيح ، فأنت تعني شيئًا كهذا:

الطبقة العامة غير آمنة
{
    كائن خاص ulock = كائن جديد ()؛

    public int Unsafe1 {get؛ جلس؛ } = 0 ؛

    private int _unsafe2 = 0 ؛
    كثافة العمليات العامة Unsafe2
    {
        احصل على
        {
            قفل (أولوك)
            {
                return _unsafe2؛
            }
        }

        جلس
        {
            قفل (أولوك)
            {
                _unsafe2 = القيمة ؛
            }
        }
    }
}

رمز الاختبار:

var u = new Unsafe ()؛

Parallel.For (0، 10000000، _ => {u.Unsafe1 ++؛})؛
Parallel.For (0، 10000000، _ => {u.Unsafe2 ++؛})؛

Console.WriteLine (string.Format ("{0} - {1}"، u.Unsafe1، u.Unsafe2))؛

النتيجة (واحد من كثير ممكن):

4648265 - 4149827

لكليهما ، اختفى أكثر من نصف التحديثات.

السبب هو أن ++ ليس ذريًا - إنها في الواقع ثلاث عمليات منفصلة:

  1. الحصول على value.Add 1 إلى value.Set القيمة.

يمكننا إصلاح ذلك عن طريق توفير عملية زيادة ذرية - هناك العديد من الطرق للقيام بذلك ، ولكن إليك طريقتان:

الطبقة العامة آمنة
{
    كائن خاص slock = كائن جديد ()؛

    Public int Safe1 {get؛ جلس؛ }
    الفراغ العام SafeIncrement1 ()
    {
        قفل (أولوك)
        {
            this.Safe1 ++؛
        }
    }

    private int _safe2 = 0 ؛
    Safe2 العام كثافة العمليات
    {
        احصل على
        {
            return _safe2 ؛
        }
        جلس
        {
            _safe2 = القيمة ؛
        }
    }
    باطلة SafeIncrement2 ()
    {
        Interlocked.Increment (ref _safe2) ؛
    }
}

رمز الاختبار:

var s = new Safe ()؛

Parallel.For (0، 10000000، _ => {s.SafeIncrement1 ()؛})؛
Parallel.For (0، 10000000، _ => {s.SafeIncrement2 ()؛})؛

Console.WriteLine (string.Format ("{0} - {1}"، s.Safe1، s.Safe2))؛

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

لاحظ أن المتغير الثاني أعلاه ، مع Interlocked.Increment ، أسرع بكثير ، ولكنه في الواقع أقل مستوى ومحدود فيما يمكن أن يفعله خارج الصندوق ؛ ومع ذلك ، يمكن استخدام العمليات في الحزمة Interlocked لتنفيذ:

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

الاجابه 2:

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

يعني الذري (إذا وصلت إلى حيث أنت ذاهب مع هذا) إنشاء مثيل واحد من كائن - لذلك بغض النظر عن عدد المرات المشار إليها ، ترى دائما مثيل واحد (من أي موضوع)


الاجابه 3:

العمليات الذرية هي وسيلة لتحقيق سلامة مؤشر الترابط إما باستخدام نوع من الأقفال مثل Mutexes أو Semaphores التي تستخدم العمليات الذرية داخليًا أو عن طريق تنفيذ التزامن الحر بدون قفل باستخدام أسوار ذرية وأسوار الذاكرة.

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

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