■ 리소스 풀(Resource Pool)을 사용하는 방법을 보여준다.
▶ ResourcePool.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; namespace TestProject { /// <summary> /// 리소스 풀 /// </summary> /// <typeparam name="TResource">리소스 타입</typeparam> public class ResourcePool<TResource> { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 병렬 백 /// </summary> private readonly ConcurrentBag<TResource> concurrentBag = new ConcurrentBag<TResource>(); /// <summary> /// 수동 리셋 이벤트 /// </summary> private ManualResetEvent manualResetEvent = new ManualResetEvent(true); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - ResourcePool(resourceList) /// <summary> /// 생성자 /// </summary> /// <param name="resourceList">리소스 리스트</param> public ResourcePool(List<TResource> resourceList) { var enumerator = resourceList.GetEnumerator(); while(enumerator.MoveNext()) { this.concurrentBag.Add(enumerator.Current); } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 구하기 - Get() /// <summary> /// 구하기 /// </summary> /// <returns>리소스</returns> public TResource Get() { TResource resource; do { if(this.concurrentBag.IsEmpty) { this.manualResetEvent.Reset(); this.manualResetEvent.WaitOne(); } } while(!this.concurrentBag.TryTake(out resource)); return resource; } #endregion #region 해제하기 - Release(resource) /// <summary> /// 해제하기 /// </summary> /// <param name="resource">리소스</param> public void Release(TResource resource) { this.concurrentBag.Add(resource); this.manualResetEvent.Set(); } #endregion } } |
▶ Resource.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
namespace TestProject { /// <summary> /// 리소스 /// </summary> public class Resource { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 카운트 /// </summary> private int count = 0; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region ID - ID /// <summary> /// ID /// </summary> public int ID { get; set; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Resource(id) /// <summary> /// 생성자 /// </summary> /// <param name="id">ID</param> public Resource(int id) { ID = id; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 카운트 증가시키기 - IncreasegCount() /// <summary> /// 카운트 증가시키기 /// </summary> public void IncreasegCount() { this.count++; } #endregion #region 문자열 구하기 - ToString() /// <summary> /// 문자열 구하기 /// </summary> /// <returns>문자열</returns> public override string ToString() { return $"ID : {ID}, Count : {this.count}"; } #endregion } } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { List<Resource> resourceList = new List<Resource>() { new Resource(0), new Resource(1), new Resource(2), new Resource(3) }; ResourcePool<Resource> resourcePool = new ResourcePool<Resource>(resourceList); Parallel.For ( 1, 50, new ParallelOptions { MaxDegreeOfParallelism = 8 }, (int index) => { Resource resource = resourcePool.Get(); resource.IncreasegCount(); Console.WriteLine($"[스레드 인덱스 : {index}] {resource.ToString()}"); Thread.Sleep(new Random().Next(600, 3000)); resourcePool.Release(resource); } ); } #endregion } } |