본문 바로가기
[ Program ]/c#스터디

59. lock / Monitor / Mutex

by 관이119 2022. 5. 11.

앞장마지막 예제에 잠시 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 클래스 - C# 프로그래밍 배우기 (Learn C# Programming)

Mutex 클래스 Mutex 클래스는 Monitor클래스와 같이 특정 코드 블럭(Critiacal Section)을 배타적으로 Locking하는 기능을 가지고 있다. 단, Monitor클래스는 하나의 프로세스 내에서만 사용할 수 있는 반면, Mut

www.csharpstudy.com

 

단일 프로세스에는 속도가 엄청나게 차이나기 때문에 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

댓글