티스토리 뷰

======================================================

안녕하세요 Doridori 입니다.


요즘 간만에 본사로 출퇴근을 하면서 안정된 생활을 하고 있습니다. 


집에서 다니니 출퇴근 시간이 만만찮은 거리기는 한데 그래도 뭔가 생활 하는 듯한 느낌?


뭔가 이게 정상적인 생활이지 라는 느낌도 들기는 하네요.


출장 생활의 장점도 분명히 존재 하기는 하지만 간간히 집에서 다니는게 필요 하기는 한듯 한 느낌입니다.


집에서 준비 하니 예제도 뭔가 좀더 집중해서 퀄이 좀 괜찮은 느낌???


좀 마음에 드네요 ㅎㅎ 


휴가 철이 다가오는데~! 


다들 한타임씩 쉬어가시고 다시 달려 보시죠~! 


화이팅!!

======================================================




48.비동기 제어 (async, await)

 

 

Source UI) Study_48_비동기 제어 (async, await) (UI).zip

Soruce 1차 Source) Study_48_비동기 제어 (async, await) (1차 Source).zip

Soruce 2차 Full Source) Study_48_비동기 제어 (async, await) (2차 Full Source).zip

교재) 48.비동기 제어 (async, await).pdf








강의 요청 나오는 내용중에 가장 많이 나오는 내용이 아닐까 싶은 비동기 제어 관련 된 내용 입니다. 


비동기 제어의 핵심은 Task와 "비동기로 호출 된 함수를 동기 처럼 처리한다" 라는 부분 인 것 같습니다.





비동기라고 하면 결국은 호출 한 함수가 종료되기 전에 다음 동작을 함께 실행 한다 라는 점인 듯 합니다. 



UI)


예전에 Class에 대해서 진행 할때 Panel에 그림을 그렸었는데 그것과 비슷한 느낌의 코드 입니다. 


그때에 비해서 동작도 많아지고 그렇네요 ㅎ


약간 공장 자동화쪽에서 물류 제어 설비의 제어코드를 맛볼 수있는 정도의 느낌으로 만들 었습니다. 


(아~ 심심한 맛이 난다~)





강의)


강의를 만들다보니 그림그리는데 시간이 너무 많이 들어간 느낌이기는 하네요. 


그림그리는데 강의 하나를 다 소비한 느낌입니다만 잘 그려 놓으면 다음에 제어 하기 편하니 일단 그려보시죠~ ^^;;


WPF의 경우 도형이 별도로 있어서 그리기 편한데 Winform의 경우 아무래도 도형을 사용 하려면 별도로 그려야 되서 확실히 불편하기는 하네요 



(1차)


처음부터 초기 화면 표시 버튼에 그림을 그리는 부분까지에 대한 내용 입니다. 





(2차 Full)








Source)

full Source 입니다.


부분부분 정리 해 놓았기 때문에 region 기준으로 검색 해서 보셔도 좋을 듯 합니다.


코드가 짧지 않기 때문에 CBase, CDoor, CRobot Class의 경우 위의 Source를 받아서 확인해 보시면 좋을것 같습니다. 


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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Sync_Ansync
{
    public partial class Form1 : Form
    {
 
        #region 전역
 
        CRobot _cRobot;  // Robot Class
        CDoor _cDoor1, _cDoor2;  // Door Class
        int _iRobot_Rotate = 0;  // Robot Rotate
        int _iSpeed = 100;  // Thread Sleep Time
        bool _bObjectExist = false;   // Robot이 Object를 가지고 있는지 여부
 
        #endregion
 
 
        public Form1()
        {
            InitializeComponent();
        }
 
 
        #region Event
 
        private void Form1_Load(object sender, EventArgs e)
        {
            // Form Load 시점에 Class 생성
            _cRobot = new CRobot("Robot");
            _cDoor1 = new CDoor("DoorLeft");
            _cDoor2 = new CDoor("DoorRight");
        }
 
        private void btn_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
 
            switch (btn.Name)
            {
                case "btnInit":
                    //fRobotDraw(_iRobot_Rotate, 0, false);
                    //fDoor1Draw(0);
                    //fDoor2Draw(0);
                    initDraw();
                    break;
                case "btnD1Open":
                    Door1Open();
                    break;
                case "btnD1Close":
                    Door1Close();
                    break;
                case "btnD2Open":
                    Door2Open();
                    break;
                case "btnD2Close":
                    Door2Close();
                    break;
                case "btnRobotE":
                    RobotArmExtend();
                    break;
                case "btnRobotR":
                    RobotArmRetract();
                    break;
                case "btnRobotRotate":
                    RobotRotate();
                    break;
                case "btnSimulation":
                    Start_Move();
                    break;
                case "btnSimulationAsync":
                    Start_Move_Async();
                    break;
                default:
                    break;
            }
        }
 
        /// <summary>
        /// 동작 속도 값 변경 시 바로 적용
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            if (int.TryParse(textBox1.Text, out int iRet))
            {
                //_iSpeed = int.Parse(textBox1.Text);
                _iSpeed = iRet;
            }
        }
        #endregion
 
 
 
        #region function
 
        /// <summary>
        /// 상태가 틀어 졌을 경우 초기 상태를 맞춰 주기 위해 추가
        /// </summary>
        private void initDraw()
        {
            _cRobot = null;
            _cDoor1 = null;
            _cDoor2 = null;
            _iRobot_Rotate = 0;
 
            _cRobot = new CRobot("Robot");
            _cDoor1 = new CDoor("DoorLeft");
            _cDoor2 = new CDoor("DoorRight");
 
            fRobotDraw(_iRobot_Rotate, 0false);
            fDoor1Draw(0);
            fDoor2Draw(0);
        }
 
        /// <summary>
        /// Panel에 Robot을 Draw
        /// </summary>
        /// <param name="iRotate"></param>
        /// <param name="iRobot_Arm_Move"></param>
        /// <param name="isObject"></param>
        private void fRobotDraw(int iRotate, int iRobot_Arm_Move, bool isObject)
        {
            this.Invoke(new Action(delegate ()
            {
                pRobot.Refresh();
 
                Graphics g = pRobot.CreateGraphics();
            
                g.FillEllipse(_cRobot.fBrushInfo(), _cRobot._rtCircle_Robot);
 
                _cRobot.fMove(iRobot_Arm_Move);
 
                Point center = new Point(100100);
                g.Transform = GetMatrix(center, iRotate);
 
                g.DrawRectangle(_cRobot.fPenInfo(), _cRobot._rtSquare_Arm);
 
                // Object가 있을 경우 표시 하고 없을 경우 표시 하지 않음
                if (isObject)
                {
                    g.FillRectangle(_cRobot.fBrushInfo(), _cRobot._rtSquare_Object);
                }
            }));
        }
 
        /// <summary>
        /// Panel에 Door 1을 Draw
        /// </summary>
        /// <param name="Move"></param>
        private void fDoor1Draw(int Move)
        {
            this.Invoke(new Action(delegate ()
            {
                pDoor1.Refresh();
 
                _cDoor1.fMove(Move);
 
                Graphics g = pDoor1.CreateGraphics();
 
                g.FillRectangle(_cDoor1.fBrushInfo(), _cDoor1._rtDoor);
                g.DrawRectangle(_cDoor1.fPenInfo(), _cDoor1._rtDoorSide);
            }));
        }
 
        /// <summary>
        /// Panel에 Door 2를 Draw
        /// </summary>
        /// <param name="Move"></param>
        private void fDoor2Draw(int Move)
        {
            this.Invoke(new Action(delegate ()
            {
                pDoor2.Refresh();
 
                _cDoor2.fMove(Move);
 
                Graphics g = pDoor2.CreateGraphics();
 
                g.FillRectangle(_cDoor2.fBrushInfo(), _cDoor2._rtDoor);
                g.DrawRectangle(_cDoor2.fPenInfo(), _cDoor2._rtDoorSide);
            }));
        }
 
 
        // Robot 회전 시 사용 하는 함수 (실제 Robot이 회전하는게 아니고 Robot Arm을 Robot 중심 기준으로 회전 시킴)
        private Matrix GetMatrix(Point centerPoint, float rotateAngle)
        {
            Matrix matrix = new Matrix();
 
            matrix.RotateAt(rotateAngle, centerPoint);
 
            return matrix;
        }
 
        #endregion
 
 
 
        #region Task
 
        /// <summary>
        /// 함수가 종료 되고 난 뒤에 다음 함수를 호출 (전체 동작을 감싸는 Task를 하나 생성 후 Task 내에서 동기 동작)
        /// </summary>
        private void Start_Move()
        {
            Task.Run(() =>
            {
                Log(enLogLevel.Info_L2, "Move Sequence Start");
 
                Door1Open();
                RobotArmExtend();
                Thread.Sleep(500);
                _bObjectExist = true;  // 팔을 뻗고 물건을 가지고 나오고
                RobotArmRetract();
                Door1Close();
                RobotRotate();
                Door2Open();
                RobotArmExtend();
                Thread.Sleep(500);
                _bObjectExist = false;  // 팔을 뻗고 물건을 놔두고 나옴
                RobotArmRetract();
                Door2Close();
                RobotRotate();
 
                Log(enLogLevel.Info_L2, "Move Sequence Complete");
            });
        }
 
 
        /// <summary>
        /// 비동기 제어 : 함수 호출 시 Task를 생성 해서 비동기로 진행 하나 필요에 따라 await를 가지고 함수의 종료를 대기
        /// </summary>
        private async void Start_Move_Async()
        {
            Log(enLogLevel.Info_L2, "Move Async Sequence Start");
 
            // 동시 동작 하는 부분의 경우 긴 시간 기준으로 대기 하도록 함
            Task vTask;
 
            vTask = Task.Run(() => RobotArmExtend());
            await Task.Run(() => Door1Open());
 
            Thread.Sleep(500);
            _bObjectExist = true;  // 팔을 뻗고 물건을 가지고 나오고
            await Task.Run(() => RobotArmRetract());
 
            vTask = Task.Run(() => Door1Close());
            await Task.Run(() => Call_RobotRotate());
 
            vTask = Task.Run(() => RobotArmExtend());
            await Task.Run(() => Call_Door2Open());
 
            Thread.Sleep(500);
            _bObjectExist = false;  // 팔을 뻗고 물건을 가지고 나오고
            await Task.Run(() => RobotArmRetract());
 
            vTask = Task.Run(() => Door2Close());
            await Task.Run(() => Call_RobotRotate());
 
            Log(enLogLevel.Info_L2, "Move Async Sequence Complete");
 
 
            /*
            //Call_RobotArmExtend();
            //await Call_Door1Open();
            Thread.Sleep(500);
            _bObjectExist = true;  // 팔을 뻗고 물건을 가지고 나오고
            await Call_RobotArmRetract();
            Call_Door1Close();
            await Call_RobotRotate();
            Call_RobotArmExtend();
            await Call_Door2Open();
            Thread.Sleep(500);
            _bObjectExist = false;  // 팔을 뻗고 물건을 놔두고 나옴
            await Call_RobotArmRetract();
            Call_Door2Close();
            await Call_RobotRotate();
            */
        }
        #endregion
 
 
 
        #region 단위 동작
 
 
        private int Door1Open()
        {
            Log(enLogLevel.Info_L1, "Door1 Open Start");
 
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(_iSpeed);
                //_iDoor1Move = -5;
                fDoor1Draw(-5);
            }
 
            Log(enLogLevel.Info_L1, "Door1 Open Complete");
 
            return 0;
        }
 
 
        private int Door1Close()
        {
            Log(enLogLevel.Info_L1, "Door1 Close Start");
 
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(_iSpeed);
                //_iDoor1Move = 5;
                fDoor1Draw(5);
            }
 
            Log(enLogLevel.Info_L1, "Door1 Close Complete");
 
            return 0;
        }
 
        /*
        // 1번 문 Open
        private async Task<int> Door1OpenAsync()
        {
            var vTask = Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(_iSpeed);
                    //_iDoor1Move = -5;
                    fDoor1Draw(-5);
                }
            });
            await vTask;
            return 0;
        }
       
        // 1번 문 Close
        private async Task<int> Door1CloseAsync()
        {
            for (int i = 0; i < 10; i++)
            {
                await Task.Delay(_iSpeed);
                //_iDoor1Move = 5;
                fDoor2Draw(5);
            }
            return 0;
        }
        */
 
        // 2번 문 Open
        private int Door2Open()
        {
            Log(enLogLevel.Info_L1, "Door2 Open Start");
 
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(_iSpeed);
                fDoor2Draw(-5);
            }
 
            Log(enLogLevel.Info_L1, "Door2 Open Complete");
 
            return 0;
        }
 
 
        // 2번 문 Close
        private int Door2Close()
        {
            Log(enLogLevel.Info_L1, "Door2 Close Start");
 
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(_iSpeed);
                fDoor2Draw(5);
            }
 
            Log(enLogLevel.Info_L1, "Door2 Close Complete");
 
            return 0;
        }
 
 
        // Robot Arm Extend (Robot의 팔을 뻗는다)
        private int RobotArmExtend()
        {
            Log(enLogLevel.Info_L1, "Robot Arm Extend Start");
 
            // Robot Arm Extend
            for (int i = 0; i < 8; i++)
            {
                Thread.Sleep(_iSpeed);
                fRobotDraw(_iRobot_Rotate, -5, _bObjectExist);
            }
 
            Log(enLogLevel.Info_L1, "Robot Arm Extend Complete");
 
            return 0;
        }
 
 
        // Robot Arm Retract (Robot의 팔을 접는다)
        private int RobotArmRetract()
        {
            Log(enLogLevel.Info_L1, "Robot Arm Retract Start");
 
            // Robot Arm Retract
            for (int i = 0; i < 8; i++)
            {
                Thread.Sleep(_iSpeed);
                fRobotDraw(_iRobot_Rotate, 5, _bObjectExist);
            }
 
            Log(enLogLevel.Info_L1, "Robot Arm Retract Complete");
 
            return 0;
        }
 
 
 
        // Robot Rotate (Robot을 회전 시킴)
        private int RobotRotate()
        {
            Log(enLogLevel.Info_L1, "Robot Rotate Start");
 
            for (int i = 0; i < 12; i++)
            {
                Thread.Sleep(_iSpeed);
                _iRobot_Rotate = _iRobot_Rotate + 15;
 
                fRobotDraw(_iRobot_Rotate, 0, _bObjectExist);
            }
 
            // 회전을 완료 한 뒤 회전각이 360을 넘어 가면 360 만큼 빼줌
            if (_iRobot_Rotate > 360) _iRobot_Rotate -= 360;
 
            Log(enLogLevel.Info_L1, "Robot Rotate Complete");
 
            return 0;
        }
 
 
 
        #endregion
 
 
 
        #region 비동기 호출 Call 함수 (필요 없지만 참고용으로 사용)
 
        private Task<int> Call_Door1Open()
        {
            var vTask = Task.Run(() => Door1Open());
 
            return vTask;
        }
 
 
        private Task<int> Call_Door1Close()
        {
            var vTask = Task.Run(() => Door1Close());
 
            return vTask;
        }
 
        private Task<int> Call_Door2Open()
        {
            var vTask = Task.Run(() => Door2Open());
 
            return vTask;
        }
 
 
        private Task<int> Call_Door2Close()
        {
            var vTask = Task.Run(() => Door2Close());
 
            return vTask;
        }
 
        private Task<int> Call_RobotArmExtend()
        {
            var vTask = Task.Run(() => RobotArmExtend());
 
            return vTask;
        }
 
 
        private Task<int> Call_RobotArmRetract()
        {
            var vTask = Task.Run(() => RobotArmRetract());
 
            return vTask;
        }
 
        private Task<int> Call_RobotRotate()
        {
            var vTask = Task.Run(() => RobotRotate());
 
            return vTask;
        }
        #endregion
 
 
 
        #region Log Viewer 
 
        // Log Level을 지정 할 Enum (44강 Tree View 참조)
        enum enLogLevel
        {
            Info_L1,
            Info_L2,
            Info_L3,
            Warning,
            Error,
        }
 
        private void Log(enLogLevel eLevel, string LogDesc)
        {
            this.Invoke(new Action(delegate ()
            {
                DateTime dTime = DateTime.Now;
                string LogInfo = $"{dTime:yyyy-MM-dd hh:mm:ss.fff} [{eLevel.ToString()}] {LogDesc}";
                lboxLog.Items.Insert(0, LogInfo);
            }));
        }
 
        private void Log(DateTime dTime, enLogLevel eLevel, string LogDesc)
        {
            this.Invoke(new Action(delegate ()
            {
                string LogInfo = $"{dTime:yyyy-MM-dd hh:mm:ss.fff} [{eLevel.ToString()}] {LogDesc}";
                lboxLog.Items.Insert(0, LogInfo);
            }));
        }
 
        #endregion
 
    }
}
 
cs


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
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
글 보관함