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

C# Queue.Synchronized() 메서드 완벽 정리 - 스레드로부터 안전한 큐 만들기

C#의 Queue.Synchronized() 메서드는 기존 큐를 감싸는(wrap) 새로운 Queue 객체를 반환합니다. 이렇게 생성된 큐는 여러 스레드가 동시에 접근해도 안전한 스레드로부터 안전한(thread-safe) 큐입니다.

구문(Syntax)

Queue.Synchronized() 메서드의 구문은 다음과 같습니다.

public static System.Collections.Queue Synchronized (System.Collections.Queue queue);

여기서 매개변수 queue는 동기화할 대상 큐를 의미합니다. 메서드 호출 시 원본 큐 자체가 수정되는 것이 아니라, 원본을 감싸는 동기화된 래퍼(wrapper) 큐가 새로 반환된다는 점에 유의하세요.

예제 1 - IsSynchronized 속성 확인하기

먼저 Queue.Synchronized() 메서드를 적용하기 전후의 IsSynchronized 속성 값 변화를 살펴보겠습니다.

using System;
using System.Collections;
public class Demo {
    public static void Main(){
        Queue queue = new Queue();
        queue.Enqueue("AB");
        queue.Enqueue("BC");
        queue.Enqueue("CD");
        queue.Enqueue("DE");
        queue.Enqueue("EF");
        queue.Enqueue("FG");
        queue.Enqueue("GH");
        queue.Enqueue("HI");
        Console.WriteLine("Queue...");
        IEnumerator demoEnum = queue.GetEnumerator();
        while (demoEnum.MoveNext()){
            Console.WriteLine(demoEnum.Current);
        }
        Console.WriteLine("Is Queue synchronized? = "+queue.IsSynchronized);
        Queue queue2 = Queue.Synchronized(queue);
        Console.WriteLine("Is Queue synchronized now? = "+queue2.IsSynchronized);
    }
}

출력 결과

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

Queue...
AB
BC
CD
DE
EF
FG
GH
HI
Is Queue synchronized? = False
Is Queue synchronized now? = True

실행 결과를 보면 일반 Queue 객체의 IsSynchronized 속성은 False이지만, Queue.Synchronized() 메서드로 감싼 후에는 True로 변경된 것을 확인할 수 있습니다.

예제 2 - 다양한 큐 연산과 함께 사용하기

이번에는 Enqueue, Contains, CopyTo 등의 연산과 함께 Queue.Synchronized() 메서드를 활용하는 예제를 살펴보겠습니다.

using System;
using System.Collections;
public class Demo {
    public static void Main(){
        Queue queue = new Queue();
        queue.Enqueue(100);
        queue.Enqueue(200);
        queue.Enqueue(300);
        Console.WriteLine("Is Queue synchronized? = "+queue.IsSynchronized);
        Queue queue2 = Queue.Synchronized(queue);
        Console.WriteLine("Is Queue synchronized now? = "+queue2.IsSynchronized);
        Console.Write("Count of elements = ");
        Console.WriteLine(queue.Count);
        Console.WriteLine("Queue...");
        foreach(int i in queue){
            Console.WriteLine(i);
        }
        Console.WriteLine("Does the queue has element 500? = "+queue.Contains(500));
        int[] intArr = new int[5];
        intArr[0] = 1;
        intArr[1] = 2;
        intArr[2] = 3;
        intArr[3] = 4;
        queue.CopyTo(intArr, 1);
        Console.WriteLine("\nQueue (Updated)");
        foreach(int i in queue){
            Console.WriteLine(i);
        }
        Console.WriteLine("\nArray (Updated)");
        foreach(int i in intArr){
            Console.WriteLine(i);
        }
    }
}

출력 결과

위 예제의 실행 결과는 다음과 같습니다.

Is Queue synchronized? = False
Is Queue synchronized now? = True
Count of elements = 3
Queue...
100
200
300
Does the queue has element 500? = False
Queue (Updated)
100
200
300
Array (Updated)
1
100
200
300
0

이 예제에서는 CopyTo(intArr, 1)를 호출하여 배열의 인덱스 1부터 큐 요소들을 복사했습니다. 따라서 업데이트된 배열은 기존 값 1이 유지되고, 그 뒤에 큐의 요소인 100, 200, 300이 순서대로 복사되며 마지막 인덱스는 초기값 0으로 남게 됩니다.

정리 및 참고 사항

Queue.Synchronized() 메서드는 .NET Framework의 비제네릭 컬렉션(System.Collections)에서 멀티스레드 환경의 데이터 경합(race condition) 문제를 방지할 때 유용하게 사용됩니다. 핵심 내용을 요약하면 다음과 같습니다.

- 반환값: 원본 큐를 감싸는 스레드로부터 안전한 새로운 Queue 객체
- IsSynchronized 속성: 동기화 전에는 False, 동기화된 래퍼 큐에서는 True 반환
- 원본 보존: 원본 큐는 그대로 유지되며, 래퍼를 통해서만 스레드 안전성이 보장됩니다

참고로 최신 C# 프로젝트에서는 제네릭 기반이면서 더 나은 성능을 제공하는 ConcurrentQueue<T>(System.Collections.Concurrent 네임스페이스) 사용이 권장됩니다. 다만 레거시 코드 유지보수 시에는 Queue.Synchronized() 메서드가 여전히 유효한 선택지가 될 수 있습니다.