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

C# ListDictionary 동기화 액세스 구현하기: SyncRoot와 lock 활용법

ListDictionarySystem.Collections.Specialized 네임스페이스에 포함된 키-값(key/value) 컬렉션으로, 내부적으로 연결 리스트 방식으로 데이터를 저장합니다. 이 컬렉션은 기본적으로 스레드로부터 안전(thread-safe)하지 않으므로, 멀티스레드 환경에서 안전하게 읽거나 쓰려면 SyncRoot 속성과 C#의 lock 문을 조합해 동기화된 액세스를 구현해야 합니다.

예제 1: SyncRoot와 lock으로 동기화된 열거

다음 예제에서는 ListDictionary에 항목을 추가한 뒤, 주요 속성(IsFixedSize, IsReadOnly, IsSynchronized)을 확인하고 lock(dict.SyncRoot) 블록 안에서 컬렉션 전체를 순회합니다.

using System;
using System.Collections;
using System.Collections.Specialized;

public class Demo {
   public static void Main() {
      ListDictionary dict = new ListDictionary();
      dict.Add("1", "SUV");
      dict.Add("2", "Sedan");
      dict.Add("3", "Utility Vehicle");
      dict.Add("4", "Compact Car");
      dict.Add("5", "SUV");
      dict.Add("6", "Sedan");
      dict.Add("7", "Utility Vehicle");
      dict.Add("8", "Compact Car");
      dict.Add("9", "Crossover");
      dict.Add("10", "Electric Car");

      Console.WriteLine("ListDictionary 요소...");
      foreach(DictionaryEntry d in dict) {
         Console.WriteLine(d.Key + " " + d.Value);
      }

      Console.WriteLine("\nListDictionary의 크기가 고정되어 있습니까? = " + dict.IsFixedSize);
      Console.WriteLine("ListDictionary가 읽기 전용입니까? = " + dict.IsReadOnly);
      Console.WriteLine("ListDictionary가 동기화되어 있습니까? = " + dict.IsSynchronized);
      Console.WriteLine("ListDictionary에 'K' 키가 있습니까? = " + dict.Contains("K"));
      Console.WriteLine("ListDictionary에 '9' 키가 있습니까? = " + dict.Contains("9"));

      Console.WriteLine("\n동기화된 액세스...");
      lock(dict.SyncRoot) {
         foreach(DictionaryEntry d in dict) {
            Console.WriteLine(d.Key + " " + d.Value);
         }
      }
   }
}

실행 결과

위 코드를 실행하면 다음과 같은 결과가 출력됩니다.

ListDictionary 요소...
1 SUV
2 Sedan
3 Utility Vehicle
4 Compact Car
5 SUV
6 Sedan
7 Utility Vehicle
8 Compact Car
9 Crossover
10 Electric Car
ListDictionary의 크기가 고정되어 있습니까? = False
ListDictionary가 읽기 전용입니까? = False
ListDictionary가 동기화되어 있습니까? = False
ListDictionary에 'K' 키가 있습니까? = False
ListDictionary에 '9' 키가 있습니까? = True

동기화된 액세스...
1 SUV
2 Sedan
3 Utility Vehicle
4 Compact Car
5 SUV
6 Sedan
7 Utility Vehicle
8 Compact Car
9 Crossover
10 Electric Car

핵심 포인트 정리

  • IsSynchronized: ListDictionary 자체의 동기화 여부를 나타내며, 기본값은 False입니다. 즉, 별도의 동기화 처리가 필요합니다.
  • SyncRoot: 컬렉션에 대한 잠금(lock)에 사용할 수 있는 객체를 반환합니다. 이 객체를 대상으로 lock 문을 작성하면 여러 스레드가 동시에 컬렉션을 수정하거나 열거하는 상황을 방지할 수 있습니다.
  • Contains(): 특정 키가 컬렉션에 존재하는지 확인합니다. 위 예제에서 'K'는 존재하지 않고 '9'는 존재함을 확인했습니다.

예제 2: 간단한 동기화 액세스 예시

이번에는 문자열 키를 사용해 더 간결한 형태로 동기화된 열거를 수행해 보겠습니다.

using System;
using System.Collections;
using System.Collections.Specialized;

public class Demo {
   public static void Main() {
      ListDictionary dict = new ListDictionary();
      dict.Add("A", "Books");
      dict.Add("B", "Electronics");
      dict.Add("C", "Appliances");
      dict.Add("D", "Pet Supplies");
      dict.Add("E", "Clothing");
      dict.Add("F", "Footwear");

      Console.WriteLine("동기화된 액세스...");
      lock(dict.SyncRoot) {
         foreach(DictionaryEntry d in dict) {
            Console.WriteLine(d.Key + " " + d.Value);
         }
      }
   }
}

실행 결과

동기화된 액세스...
A Books
B Electronics
C Appliances
D Pet Supplies
E Clothing
F Footwear

마무리

ListDictionary는 소규모 컬렉션에서 빠른 성능을 제공하지만, 기본적으로 동기화되지 않으므로 멀티스레드 환경에서는 반드시 lock(dict.SyncRoot) 패턴을 사용해야 합니다. 참고로 스레드 안전성이 중요한 최신 .NET 개발에서는 System.Collections.Concurrent 네임스페이스의 ConcurrentDictionary<TKey, TValue>를 대안으로 고려하는 것도 좋은 방법입니다.