Używanie instrukcji lock w pętli w C #
Weźmy przykładową klasę SomeThread, w której próbujemy uniemożliwić wywoływanie metod DoSomething po ustawieniu właściwości Running na false, a Dispose jest wywoływane przez klasę OtherThread, ponieważ jeśli zostaną wywołane po metodzie Dispose, świat skończy się, gdy znać to.
Wydaje się, że z powodu pętli istnieje szansa na coś złego. Że w momencie, w którym rozpoczyna następną pętlę i przed wykonaniem blokady przed wywołaniem metod DoSomething, Uruchomienie może zostać zmienione na false, a Disposed wywołane zanim trafi w zamek. W tym scenariuszu życie nie byłoby dobre.
Szukałem sposobów, aby sobie z tym poradzić, używając pętli w prostej, łatwej do utrzymania metodzie. Dla rekordu wziąłem pod uwagę wzorzec sprawdzania podwójnej blokady, jednak wydaje się, że nie jest on zalecany dla C #.
Ostrzeżenie: Jest to uproszczony przykład, aby ułatwić skupienie się na problemie z pętlą i blokowaniem w jednym. Jeśli nie opracowałem wystarczająco miejsca, daj mi znać, a zrobię wszystko, co w mojej mocy, aby wypełnić wszelkie szczegóły.
public class SomeThread : IDisposable
{
private object locker = new object();
private bool running = false;
public bool Running
{
get
{
lock(locker)
{
return running;
}
}
set
{
lock(locker)
{
running = value;
}
}
}
public void Run()
{
while (Running)
{
lock(locker)
{
DoSomething1();
DoSomething2();
}
}
}
private void DoSomething1()
{
// something awesome happens here
}
private void DoSomething2()
{
// something more awesome happens here
}
public void Dispose()
{
lock (locker)
{
Dispose1();
Dispose2();
}
}
private void Dispose1()
{
// something awesome happens here
}
private void Dispose2()
{
// something more awesome happens here
}
}
public class OtherThread
{
SomeThread st = new SomeThread();
public void OnQuit()
{
st.Running = false;
st.Dispose();
Exit();
}
}