آلية القفل التي توفر معلومات حول الحالة في .NET 3.5

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

  •  29-09-2019
  •  | 
  •  

سؤال

أحاول إيجاد طريقة لتوفير وصول حصري إلى مورد ، بينما في نفس الوقت تقديم معلومات حول حالة القفل (_isworking) لقراءة الفصول الأخرى.

هذا ما توصلت إليه حتى الآن:

    private int _isWorking = 0;

    public bool IsWorking
    {
        get { return Interlocked.CompareExchange(ref _isWorking, 0, 0) == 1; }
    }

    public void LaunchProcess()
    {
        if (Interlocked.CompareExchange(ref _isWorking, 1, 0) == 0)
        {
            try
            {
                DoExpansiveProcess();
            }
            finally
            {
                Interlocked.Exchange(ref _isWorking, 0);
            }
        }
    }

    public void DoExpansiveProcess()
    {
        Thread.Sleep(30000);
    }

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

هل هي الطريقة الصحيحة للقيام بذلك أم أن هناك أي بنية C# 3.5 أكثر تكييفًا لهذا الغرض؟

وكيفية تنفيذ سيناريو قفل "حقيقي" ، حيث لا يزال الخيط الثاني ينفذ الطريقة بعد الانتهاء من أول واحد ، مع توفير معلومات حول الحالة؟

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

المحلول

على افتراض أنني أفهم سؤالك بشكل صحيح ثم أعتقد أن ما أنت عليه هو Monitor.TryEnter الطريقة ذات قيمة مهلة 0. ستحاول الحصول على القفل ، ولكن مع مهلة 0 ، ستعود دائمًا على الفور بقيمة تشير إلى ما إذا كان قد تم الحصول على القفل بالفعل. المعنى الضمني هنا هو أنه إذا لم يتم الحصول على القفل ، فمن المفترض أنه تم الحصول عليه بالفعل من قبل شخص آخر. المشكلة هي أنه في حالة عودة true ثم يجب عليك إصدارها فورًا باستخدام مكالمة إلى Monitor.Exit.

ربما سيكون هذا حلاً أفضل:

public class Worker
{
  private Object m_LockObject = new Object();
  private volatile bool m_IsWorking = false;

  public bool IsWorking
  {
    get { return m_IsWorking; }
  }

  public void LaunchProcess()
  {
    lock (m_LockObject)
    {
      m_IsWorking = true;
      DoExpansiveProcess();
      m_IsWorking = false;
    }
  }
}

نصائح أخرى

System.Threading.ManualResetEvent قد تكون قادرة على المساعدة هنا. فقط افعل waitone () ضدها. إذا تم استخدامه ، فسوف يعود كخطأ. إذا لم يكن قيد الاستخدام ، فهو متاح.

يستغرق أحد الحمولة الزائدة في Waitone () وقتًا في المللي ثانية للانتظار. إذا كنت تستخدم Waitone (0) ، فسيعود الانتظار على الفور بطريقة غير حظر.

يجب عليك إجراء بعض الأبحاث في بدائل التزامن التي يقدمها .NET:

System.Threading.Monitor lock() { }
System.Threading.ManualResetEvent
System.Threading.AutoResetEvent
System.Threading.Semaphore
System.Threading.Mutex

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

لجعل هذا النهج آمنًا ، يجب أن يكون العمل خاصًا.

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