Computer >> 컴퓨터 >  >> 프로그래밍 >> C#

C# StringCollection 동기화 액세스 구현 방법 – SyncRoot와 lock 활용하기

C#의 StringCollection은 기본적으로 스레드로부터 안전(thread-safe)하지 않은 컬렉션입니다. 따라서 여러 스레드가 동시에 동일한 컬렉션에 접근하는 환경에서는 SyncRoot 속성과 lock 문을 사용하여 동기화된 액세스를 구현해야 합니다. SyncRoot는 컬렉션에 대한 동기화를 수행하는 데 사용되는 전용 객체를 반환하며, 이를 lock 블록으로 감싸면 한 번에 하나의 스레드만 컬렉션에 접근할 수 있습니다.

예제 1: 배열 요소 추가 후 동기화 액세스로 순회하기

using System;
using System.Collections.Specialized;
public class Demo {
    public static void Main() {
        StringCollection stringCol = new StringCollection();
        String[] arr = new String[] { "100", "200", "300", "400", "500" };
        Console.WriteLine("Array elements...");
        foreach (string res in arr) {
            Console.WriteLine(res);
        }
        stringCol.AddRange(arr);
        Console.WriteLine("Total number of elements = "+stringCol.Count);
        stringCol.RemoveAt(3);
        Console.WriteLine("Total number of elements now = "+stringCol.Count);
        Console.WriteLine("Synchronize access...");
        lock(stringCol.SyncRoot) {
            foreach(object ob in stringCol) {
                Console.WriteLine(ob);
            }
        }
    }
}

실행 결과

위 코드를 실행하면 다음과 같은 출력이 생성됩니다.

Array elements...
100
200
300
400
500
Total number of elements = 5
Total number of elements now = 4
Synchronize access...
100
200
300
500

위 예제에서는 먼저 문자열 배열을 만들어 AddRange() 메서드로 StringCollection에 한 번에 추가했습니다. 이후 RemoveAt(3)을 호출하여 인덱스 3(값 400)의 요소를 삭제했고, 마지막으로 lock(stringCol.SyncRoot) 블록 안에서 foreach 루프를 통해 모든 요소를 안전하게 출력했습니다.

예제 2: Add 메서드로 요소 추가 후 동기화 액세스

이번에는 Add() 메서드로 개별 문자열을 하나씩 추가하고, 같은 방식으로 동기화된 액세스를 적용해 보겠습니다.

using System;
using System.Collections.Specialized;
public class Demo {
    public static void Main() {
        StringCollection strCol = new StringCollection();
        strCol.Add("Katie");
        strCol.Add("Philips");
        strCol.Add("Jacob");
        strCol.Add("Carl");
        strCol.Add("Gary");
        Console.WriteLine("Synchronize access...");
        lock(strCol.SyncRoot) {
            foreach(object ob in strCol) {
                Console.WriteLine(ob);
            }
        }
    }
}

실행 결과

Synchronize access...
Katie
Philips
Jacob
Carl
Gary

핵심 정리

  • SyncRoot: 컬렉션 내부의 동기화 객체를 반환하며, 외부 코드에서 lock 대상으로 사용됩니다.
  • lock 문: 임계 영역(critical section)을 지정하여 한 번에 하나의 스레드만 해당 블록을 실행하도록 보장합니다.
  • 열거 중 안전성: foreach로 컬렉션을 순회하는 도중 다른 스레드가 요소를 수정하면 오류가 발생할 수 있으므로, 순회 시 반드시 SyncRoot로 잠그는 것이 좋습니다.

이처럼 StringCollection을 멀티스레드 환경에서 사용할 때는 SyncRoot 속성과 lock 문을 함께 활용하면 데이터 경합(race condition)과 예기치 않은 예외를 효과적으로 방지할 수 있습니다.