앞장마지막 예제에 잠시 Monitor 클래스를 사용하는 예제를 넣었다.
3가지다 간단하게 말하면 다른곳에서 변경못하게 잠궈놓는 역할을 하는것들이다.
아래 예제를 보자.
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
|
#define lock1
#define type2
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp13
{
public partial class Form12 : Form
{
int _num = 0;
object _obj = new object();
private Mutex _mtx = new Mutex(false, "MutexName1");
public Form12()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_num = 0;
for (int i =0;i<100;i++)
{
Task.Run(() => changenum());
}
}
public void changenum()
{
#if lock1
lock (_obj)
{
_num++;
}
#elif lock2
Monitor.Enter(_obj);
_num++;
Monitor.Exit(_obj);
#elif lock3
_mtx.WaitOne();
_num++;
_mtx.ReleaseMutex();
#endif
label_text_change(label1, _num.ToString());
}
public void label_text_change(Label lb, string i)
{
if (lb.InvokeRequired)
{
#if type1
Action ac = new Action(delegate () { lb.Text = i; });
lb.Invoke(ac);
#elif type2
lb.Invoke(new Action(delegate () { lb.Text = i; }));
#elif type3
lb.Invoke((Action)delegate () { lb.Text = i; });
#elif type4
lb.Invoke((MethodInvoker)delegate () { lb.Text = i; });
#elif type5
lb.Invoke((Action<string>)delegate (string s) { lb.Text = s; }, i);
#endif
}
else
{
lb.Text = i;
}
}
private void button2_Click(object sender, EventArgs e)
{
label_text_change(label1, "0");
}
}
}
|
cs |
위 소스에서 보면 button1 클릭시 100개의 task 를 실행시키면서 전역변수 _num 의 숫자를 증가시키고 있다.
그런데 이 작업이 lock 없이 실행되면 최종결과값이 100이 나오지 않을수 있다.
task 가 실행되는순간의 _num 값이 실제 최종값이 아닐수 있다는 의미이다.
3개의 task가 동시에 실행된다고 생각하면 3개의 처리속도는 모두 동일하지는 않다.
즉, task1 이 시작되자마자 _num 값을 가져오면 0 일것이다.
이후에 _num 을 ++ 하면 _num 이 1 이된다.
그런데 이작없을 하는 도중에 만약에 task2 에서 _num 의 값을 가져오면 아직 ++ 이 반영되지않은 0 값을 가져와서 ++ 작업을 해서 1 을 반환해버릴수 있다.
즉, task1 과 task2 가 동시에 같은 변수를 변경하게 되면 양쪽다 ++ 작업을하지만 최종 결과값이 2가 아닌 1이 되버릴수 있다.
이렇게 동시 작업으로 인한 이상작업을 방지하기 위해 lock 을 사용한다.
변수가 lock 이 되면 내부적으로는 어떻게 작동할지 정확하게 알수는 없지만 위에서 설명한 내용일 경우 task2 가 lock 이 풀릴때까지 기다린다고 예상할 수 있다.
동시작업으로 인한 문제가 없어지면 결국 위 예제를 실행한것처럼 예상할 수 있는 정상적인 결과값을 얻을 수 있다.
Mutex 같은 경우는 lock 과 약간 다른데 아래 글을 읽어보자.
https://www.csharpstudy.com/Threads/mutex.aspx
단일 프로세스에는 속도가 엄청나게 차이나기 때문에 mutex 를 사용하지 말라고 되어있다.
해당부분만 주의해서 사용하면 전체 내용은 특별한 부분은 없다.
대부분의 경우 프로그램 중복실행시만 mutex 로 체크하고 그외는 lock 을 사용하면 되낟.
***숙제 : lock 을 사용하는 프로그램을 만들어보자. 중복실행 방지하는 부분도 만들어보자.
'[ Program ] > c#스터디' 카테고리의 다른 글
61. 이벤트 (0) | 2022.05.18 |
---|---|
60. 유저컨트롤 (0) | 2022.05.17 |
58. Threadpool / BackgroundWorker / Parallel (0) | 2022.05.11 |
57. async / await (0) | 2022.03.29 |
56. 쓰레드2(Task) (0) | 2022.02.27 |
댓글