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를 하는 게 원칙이다.