■ 쓰기/읽기 작업을 비동기 순차 처리하는 방법을 보여준다.
작업 조건이 아래와 같은 경우를 위한 비동기 순차 처리 코드이다.
. 1번 쓰기 작업 완료 후 1번 읽기 작업을 할 수 있고 2번 쓰기 작업 완료 후 2번 읽기 작업을 할 수 있다.
. 1번 쓰기 작업 완료 후 2번 쓰기 작업을 할 수 있고 2번 쓰기 작업 완료 후 3번 쓰기 작업을 할 수 있다.
. 1번 읽기 작업 완료 후 2번 읽기 작업을 할 수 있고 2번 읽기 작업 완료 후 3번 읽기 작업을 할 수 있다.
. 쓰기 작업은 동시에 50개까지 할 수 있다.
. 읽기 작업은 동시에 50개까지 할 수 있다.
. 모든 쓰기/읽기 작업이 완료될 때까지 프로그램 종료를 보류한다.
▶ 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 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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
using System; using System.Collections.Generic; using System.Threading; namespace TestProject { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 난수 발생기 /// </summary> /// <remarks>작업 시간을 임의로 설정하기 위한 것이다.</remarks> private static Random _random = null; /// <summary> /// 쓰기 자동 리셋 이벤트 딕셔너리 /// </summary> /// <remarks>첫번째 쓰기 작업이 끝나기 전에 두번째 쓰기 작업이 시작되는 것을 방지하기 위한 것이다.</remarks> private static Dictionary<int, AutoResetEvent> _writeAutoResetEventDictionary = null; /// <summary> /// 읽기 자동 리셋 이벤트 딕셔너리 /// </summary> /// <remarks>첫번째 읽기 작업이 끝나기 전에 두번째 읽기 작업이 시작되는 것을 방지하기 위한 것이다.</remarks> private static Dictionary<int, AutoResetEvent> _readAutoResetEventDictionary = null; /// <summary> /// 카운트 다운 이벤트 /// </summary> /// <remarks>모든 쓰기/읽기 작업이 완료될 때까지 대기하기 위한 것이다.</remarks> private static CountdownEvent _countdownEvent = null; /// <summary> /// 쓰기 세마포어 /// </summary> /// <remarks>동시에 처리 가능한 쓰기 작업 수를 제한하기 위한 것이다.</remarks> private static SemaphoreSlim _writeSemaphore = new SemaphoreSlim(50); /// <summary> /// 읽기 세마포어 /// </summary> /// <remarks>동시에 처리 가능한 읽기 작업 수를 제한하기 위한 것이다.</remarks> private static SemaphoreSlim _readSemaphore = new SemaphoreSlim(50); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 데이터 쓰기 - WriteData(parameter) /// <summary> /// 데이터 쓰기 /// </summary> /// <param name="parameter">매개 변수</param> private static void WriteData(object parameter) { int i = (int)parameter; try { if(i > 0) { _writeAutoResetEventDictionary[i - 1].WaitOne(); } // 임의 작업을 한 것으로 가정한다. Thread.Sleep(_random.Next(30, 100)); Console.WriteLine(i.ToString() + "번 쓰기 작업을 완료했습니다."); _readSemaphore.Wait(); Thread thread = new Thread(new ParameterizedThreadStart(ReadData)); thread.Start(i); } finally { _writeAutoResetEventDictionary[i].Set(); _writeSemaphore.Release(); } } #endregion #region 데이터 읽기 - ReadData(Parameter) /// <summary> /// 데이터 읽기 /// </summary> /// <param name="parameter">매개 변수</param> private static void ReadData(object parameter) { int i = (int)parameter; try { if(i > 0) { _readAutoResetEventDictionary[i - 1].WaitOne(); } Thread.Sleep(_random.Next(30, 100)); Console.WriteLine(i.ToString() + " 차트 읽기 작업을 완료했습니다."); } finally { _readAutoResetEventDictionary[i].Set(); _countdownEvent.Signal(); _readSemaphore.Release(); } } #endregion #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { _random = new Random(); // 처리할 작업 수를 설정한다. int threadCount = 100; // 작업을 순차적으로 처리하기 위한 쓰기/읽기 동기 객체 딕셔너리를 초기화 한다. _writeAutoResetEventDictionary = new Dictionary<int, AutoResetEvent>(); _readAutoResetEventDictionary = new Dictionary<int, AutoResetEvent>(); for(int i = 0; i < threadCount; i++) { _writeAutoResetEventDictionary.Add(i, new AutoResetEvent(false)); _readAutoResetEventDictionary.Add(i, new AutoResetEvent(false)); } // 모든 쓰기/읽기 작업이 완료될 때까지 대기하기 위한 동기 객체를 초기화 한다. _countdownEvent = new CountdownEvent(threadCount); // 작업을 처리한다. for(int i = 0; i < threadCount; i++) { Console.WriteLine(i.ToString() + "번 작업을 시작합니다."); _writeSemaphore.Wait(); Thread writeThread = new Thread(new ParameterizedThreadStart(WriteData)); writeThread.Start(i); Thread.Sleep(200); } // 모든 쓰기/읽기 작업이 완료될 때까지 대기한다. _countdownEvent.Wait(); Console.WriteLine("작업을 완료했습니다."); } #endregion } } |