c# DataTable의 뜨레드 안정성
아래의 코드는 디버그 모드에서 제대로 작동하지 않지만 크로스-뜨레드 예외로 처리되지도 않는다. 릴리스 모드에서는 정상으로 작동한다.
DataTable DataTable1 = new();
private void Form1_Load(object sender, EventArgs e)
{
DataTable1.Columns.Add("0");
dataGridView1.DataSource = DataTable1;
}
private void Form1_Click(object sender, EventArgs e)
{
Task task = new(Method1);
task.Start();
}
void Method1()
{
DataRow dataRow = DataTable1.Rows.Add();
dataRow["0"] = "a";
}
아래와 같이 하면 디버그 모드에서도 잘 된다.
void Method1()
{
Invoke(DataRowAdd);
}
void DataRowAdd()
{
DataRow dataRow = DataTable1.Rows.Add();
dataRow["0"] = "a";
}
DataTable은 뜨레드에서 안전하지 않은데 다른 비주얼 컨트롤들과는 달리 크로스-뜨레드 예외로 처리되지 않고 상황에 따라 다르게 몇몇의 예외로 처리되거나 위의 예제에서처럼 아예 조용하다. 그럼에도 불구하고 이것은 크로스-뜨레드 문제이며 다른 예외 처리에 정신을 팔리거나 유의하지 않으면 크로스-뜨레드 문제로 풀어야 할 생각을 못 할 수 있다.
DataRow를 추가할 때는 위와 같이 엉뚱한 작동으로 금방 확인이 되지만 아래의 예제는 좀 더 복잡하다. 예외로 처리가 되기도 하고 안 되기도 한다.
DataTable DataTable1 = new();
private void Form1_Load(object sender, EventArgs e)
{
DataTable1.Columns.Add("0", typeof(Int32));
DataTable1.Rows.Add("1");
dataGridView1.DataSource = DataTable1;
}
private void Form1_Click(object sender, EventArgs e)
{
Task task1 = new(Method1);
Task task2 = new(Method1);
task1.Start();
task2.Start();
}
void Method1()
{
dataRow["0"] = (int)dataRow["0"] + 1;
}
서로 레이스를 할 때에만 오류로 처리된다. 아래와 같이 하면 오류를 피할 수 있다.
void Method1()
{
DataRow dataRow = DataTable1.Rows[0];
lock (dataGridView1)
{
dataRow["0"] = (int)dataRow["0"] + 1;
}
}
메인 뜨레드 아닌 뜨레드에서 비주얼 컨트롤을 건드릴 때는 invoke를 하는 게 원칙이다.