성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 그냥 RSS Reader 기능과 약간의 UI 편의성 때문에 사용...
[이종효] 오래된 소프트웨어는 보안 위협이 되기도 합니다. 혹시 어떤 기능...
[정성태] @Keystroke IEEE의 문서를 소개해 주시다니... +_...
[손민수 (Keystroke)] 괜히 듀얼채널 구성할 때 한번에 같은 제품 사라고 하는 것이 아...
[정성태] 전각(Full-width)/반각(Half-width) 기능을 토...
[정성태] Vector에 대한 내용은 없습니다. Vector가 닷넷 BCL...
[orion] 글 읽고 찾아보니 디자인 타임에는 InitializeCompon...
[orion] 연휴 전에 재현 프로젝트 올리자 생각해 놓고 여의치 않아서 못 ...
[정성태] 아래의 글에 정리했으니 참고하세요. C# - Typed D...
[정성태] 간단한 재현 프로젝트라도 있을까요? 저런 식으로 설명만 해...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>.NET에서 Producer/Consumer를 구현하는 기초 인터페이스 - IProducerConsumerCollection<T></h1> <p> IProducerConsumerCollection<T>은,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > IProducerConsumerCollection<T> Interface ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.iproducerconsumercollection-1'>https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.iproducerconsumercollection-1</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public interface IProducerConsumerCollection<T> : IEnumerable<T>, IEnumerable, ICollection { void CopyTo(T[] array, int index); T[] ToArray(); bool TryAdd(T item); bool TryTake([MaybeNullWhen(false)] out T item); } </pre> <br /> 단순히 생각하면 기존의 ICollection 구현에서 (대표적으로) TryAdd, TryTake와 CopyTo, ToArray 메서드를 추가한 유형입니다. 즉, 이름과 어울릴법한 Producer/Consumer를 위한 특정 메서드가 추가된 것은 아닙니다. 얼핏 인터페이스의 이름만 봐서는 TryAdd/TryTake 메서드를 어떤 식으로 구현해야 할지 감도 잘 안 옵니다.<br /> <br /> 사실, 엄밀히 말하면 IProducerConsumerCollection<T>보다는 IConcurrentCollection<T>가 더 어울릴 것입니다. 또는 좀 더 직접적으로 말하면 IThreadSafeCollection도 나쁘지 않은 이름입니다. 아마도 그랬다면 TryAdd나 TryTake(를 비롯해 기타 ICollection 구현) 메서드가 thread-safe해야 한다는 것을 단번에 알아챌 수 있었을 것입니다.<br /> <br /> 물론, 대개의 경우 Producer/Consumer 구현은 스레드에 걸쳐 사용된다는 점에서 그나마 IProducerConsumerCollection의 정당성이 부여됩니다. 가령 A 스레드가 데이터를 생성하고, B 스레드에서 그 데이터를 소비하는 식이므로, 이로 인해 Thread-safe한 성격을 가진 데이터 구조가 필요하고, 그중에서도 Collection인 경우 특별히 IProducerConsumerCollection<T> 인터페이스를 구현하도록 의도한 것입니다.<br /> <br /> 실제로 "<a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.iproducerconsumercollection-1'>IProducerConsumerCollection<T> Interface</a>" 문서의 예제 코드를 봐도, <br /> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public class SafeStack<T> : IProducerConsumerCollection<T> { private readonly object m_lockObject = new object(); private readonly Stack<T> m_sequentialStack; public SafeStack() { m_sequentialStack = new Stack<T>(); } public SafeStack(IEnumerable<T> collection) { m_sequentialStack = new Stack<T>(collection); } public void Push(T item) { lock (m_lockObject) m_sequentialStack.Push(item); } public bool TryPop(out T? item) { bool rval = true; lock (m_lockObject) { if (m_sequentialStack.Count == 0) { item = default(T); rval = false; } else { item = m_sequentialStack.Pop(); } } return rval; } public bool TryTake([MaybeNullWhen(false)] out T item) { return TryPop(out item); } public bool TryAdd(T item) { Push(item); return true; // Push doesn't fail } public T[] ToArray() { lock (m_lockObject) { return m_sequentialStack.ToArray(); } } public void CopyTo(T[] array, int index) { lock (m_lockObject) m_sequentialStack.CopyTo(array, index); } public IEnumerator<T> GetEnumerator() { lock (m_lockObject) { return new Stack<T>(m_sequentialStack).GetEnumerator(); } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<T>)this).GetEnumerator(); } public bool IsSynchronized { get { return true; } } public object SyncRoot { get { return m_lockObject; } } public int Count { get { return m_sequentialStack.Count; } } public void CopyTo(Array array, int index) { lock (m_lockObject) ((ICollection)m_sequentialStack).CopyTo(array, index); } } </pre> <br /> 단순히 기존의 Stack<T> 자료구조에 thread-safe 기능만 얹어 SafeStack<T>를 만들어 IProducerConsumerCollection<T> 인터페이스를 적용하고 있습니다. 또한, 닷넷 BCL의 System.Collections.Concurrent 네임스페이스에서 제공하는 컬렉션도 모두,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentbag-1'>System.Collections.Concurrent.ConcurrentBag<T></a> <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1'>System.Collections.Concurrent.ConcurrentQueue<T></a> <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentstack-1'>System.Collections.Concurrent.ConcurrentStack<T></a> </pre> <br /> IProducerConsumerCollection<T>을 상속받고 있습니다.<br /> <br /> 아마 여러분들도 그동안 컬렉션 중에 thread-safe가 필요해서 동기화를 시킨 컬렉션들이 있을 것입니다. 그것들 모두가 잠재적으로는 IProducerConsumerCollection<T> 인터페이스를 상속받아도 무방한 것입니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1918
(왼쪽의 숫자를 입력해야 합니다.)