c# 대이터 래이스를 막는 lock의 유효 범위
아래의 코드는 대이터 래이스를 일어나게 하는 예제다. start debugging을 하면 오류로 인해 실행되지 않고 start without debugging을 하면 대이터 래이스를 확인할 수 있다.
class TestClass
{
public List<int> Ints = new();
}
TestClass TestClass1 = new();
private void button1_Click(object sender, EventArgs e)
{
Method1();
Method2();
}
void Method1()
{
Task task = new(ThreadedMethod1);
task.Start();
}
void Method2()
{
Task task = new(ThreadedMethod1);
task.Start();
}
void ThreadedMethod1()
{
for (int i = 0; i < 50; i++)
{
TestClass1.Ints.Add(i);
textBox1.AppendText(TestClass1.Ints[i].ToString() + "\r\n");
}
}
void ThreadedMethod2()
{
for (int i = 0; i < 50; i++)
{
TestClass1.Ints.Add(i);
textBox1.AppendText(TestClass1.Ints[i].ToString() + "\r\n");
}
}
위 예제에서 TestClass1은 서로 다른 뜨레드에서 실행되는 서로 다른 메떠드로 보내진다. 서로 다른 뜨레드에서 실행되는 하나의 메떠드에서는 lock으로 쉽게 대이터 래이스를 막을 수 있지만 위와 같은 경우에도 그럴까?
그렇다. 아래의 코드는 대이터 래이스를 일으키지 않는다.
void ThreadedMethod1()
{
lock (TestClass1)
{
for (int i = 0; i < 50; i++)
{
TestClass1.Ints.Add(i);
textBox1.AppendText(TestClass1.Ints[i].ToString() + "\r\n");
}
}
}
void ThreadedMethod2()
{
lock (TestClass1)
{
for (int i = 0; i < 50; i++)
{
TestClass1.Ints.Add(i);
textBox1.AppendText(TestClass1.Ints[i].ToString() + "\r\n");
}
}
}
lock은 어떤 뜨레드에서 어떤 메떠드가 실행되든 lock의 대상이 되는 객체는 완전하게 동기화한다. 즉 대이터 래이스를 막고 순서대로 처리한다.