https://learn.microsoft.com/ko-kr/dotnet/csharp/advanced-topics/interop/using-type-dynamic

 

유형 동적 사용 - C#

동적 형식을 사용하는 방법을 알아봅니다. 동적 형식은 정적 형식이지만 동적 개체는 정적 형식 검사를 무시합니다.

learn.microsoft.com

클래스든 변수든 dynamic 하나로 이용가능.

Object 형식의 경우 Cast 따위 필요없다.

https://learn.microsoft.com/ko-kr/dotnet/api/system.tuple-3?view=net-7.0

 

Tuple<T1,T2,T3> Class (System)

Represents a 3-tuple, or triple.

learn.microsoft.com

이벤트 매개변수로 등 다수의 서로 다른 자료형의 데이터를  매개변수로 전달 할 때 유용.

따로 클래스나 구조체를 정의하지 않고도 사용할 수 있기에 편하다.

 

https://learn.microsoft.com/ko-kr/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-8.0

 

ConcurrentQueue<T> 클래스 (System.Collections.Concurrent)

스레드로부터 안전한 FIFO(첫 번째 출력) 컬렉션을 나타냅니다.

learn.microsoft.com

여러 스레드에서 접근시 충돌방지.

프로그램 제작 후 방화벽 때문에 허용되는 앱을 등록 할 떄가 있다.

방화벽에서 앱 허용.. 귀찮다.

매번 하기 귀찮아 방법을 찾아보았다.

코드로 가능한가 해서 찾아보니 요기잉네

https://csharp.hotexamples.com/examples/-/INetFwMgr/-/php-inetfwmgr-class-examples.html

 

아래 올려둔 코드는 해당 클래스를 static으로 변경해 놓은거다. 

AddProgram 함수도 쪼끔 바꿔놨으니 아래코드 가져다 쓰시면 된다.

 

일단 참조에 NetFwTypeLib을 추가해준다. 

참조추가

더보기

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetFwTypeLib;

public static class FirewallHandler
{
    #region Fields

        // ProgID for the AuthorizedApplication object
        private const string PROGID_AUTHORIZED_APPLICATION = "HNetCfg.FwAuthorizedApplication";
        private const string PROGID_OPEN_PORT = "HNetCfg.FWOpenPort";

        private static INetFwMgr _fwMgr;

        #endregion Fields

        #region Constructors


        #endregion Constructors

        #region Methods

        public static bool AddPort(string title, int portNo, bool isUDP)
        {
            bool result = false;
            INetFwOpenPort port = _GetPort(title, portNo, isUDP);
            INetFwMgr manager = _GetFirewallManager();
            try
            {
                manager.LocalPolicy.CurrentProfile.GloballyOpenPorts.Add(port);
                result = true;
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return result;
        }
         /// <summary>
        /// 방화벽에 프로그램을 추가합니다.
        /// </summary>
        /// <param name="title">Application.ProductName + ".exe"</param>
        /// <param name="applicationPath">Application.ExecutablePath</param>
        /// <returns></returns>
        public static bool AddProgram(string title, string applicationPath)
        {
            bool exist = false;
            INetFwAuthorizedApplication auth = _GetAuth(title, applicationPath);

            _fwMgr = _GetFirewallManager();

            try
            {                               
                //           
                foreach (INetFwAuthorizedApplication mApp in _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications)
                {
                    if (auth == mApp)
                    {
                        exist = true;
                        break;
                    }
                }
                if (!exist)
                {                    
                    _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications.Add(auth);
                    foreach (INetFwAuthorizedApplication mApp in _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications)
                    {
                        if (auth == mApp)
                        {
                            exist = true;
                            break;
                        }
                    }
                }
                if (!exist)
                {
                    _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications.Add(auth);
                    foreach (INetFwAuthorizedApplication mApp in _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications)
                    {
                        if (auth == mApp)
                        {
                            exist = true;
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return exist;
        }

        public static bool DisableFirewall()
        {
            return _SetEnableFirewall(false);
        }

        public static bool EnableFirewall()
        {
            return _SetEnableFirewall(true);
        }

        public static string GetByPort(int _port)
        {
            string portName = null;
            try
            {
                _fwMgr = _GetFirewallManager();
                foreach (INetFwOpenPort port in _fwMgr.LocalPolicy.CurrentProfile.GloballyOpenPorts)
                {
                    if (port.Port == _port)
                    {
                        portName = port.Name;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return portName;
        }

        public static string GetByProgramPath(string fileName)
        {
            string programName = null;
            try
            {
                _fwMgr = _GetFirewallManager();
                foreach (INetFwAuthorizedApplication app in _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications)
                {
                    if (fileName.ToLower().Equals(app.ProcessImageFileName.ToLower()))
                    {
                        programName = string.Format("{0}[{1}]", app.Name, app.ProcessImageFileName);
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return programName;
        }

        public static List GetPortList()
        {
            List aList = new List();
            try
            {
                _fwMgr = _GetFirewallManager();
                foreach (INetFwOpenPort port in _fwMgr.LocalPolicy.CurrentProfile.GloballyOpenPorts)
                {
                    aList.Add(port.Name + ":" + port.Port);
                }
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return aList;
        }

        public static List GetProgramList()
        {
            List aList = new List();
            try
            {
                _fwMgr = _GetFirewallManager();
                foreach (INetFwAuthorizedApplication app in _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications)
                {
                    aList.Add(app.Name + ":" + app.ProcessImageFileName);
                }
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return aList;
        }

        public static bool IsFirewallEnabled()
        {
            _fwMgr = _GetFirewallManager();

            return _fwMgr.LocalPolicy.CurrentProfile.FirewallEnabled;
        }

        public static bool RemovePort(int portNo, bool isUDP)
        {
            bool result = false;
            INetFwMgr manager = _GetFirewallManager();
            NET_FW_IP_PROTOCOL_ protocol = isUDP ? NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP : NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
            try
            {
                manager.LocalPolicy.CurrentProfile.GloballyOpenPorts.Remove(portNo, protocol);
                result = true;
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return result;
        }

        public static bool RemoveProgram(string applicationPath)
        {
            bool result = false;
            _fwMgr = _GetFirewallManager();

            try
            {
                _fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications.Remove(applicationPath);
                result = true;
            }
            catch (Exception ex)
            {
                //MsgrLogger.WriteLog(ex.ToString());
            }
            return result;
        }

        private static INetFwAuthorizedApplication _GetAuth(string title, string applicationPath)
        {
            // Create the type from prog id
            Type type = Type.GetTypeFromProgID(PROGID_AUTHORIZED_APPLICATION);
            INetFwAuthorizedApplication auth = Activator.CreateInstance(type)
                as INetFwAuthorizedApplication;
            auth.Name = title;
            auth.ProcessImageFileName = applicationPath;
            auth.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
            auth.IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY;
            auth.Enabled = true;

            return auth;
        }

        private static INetFwMgr _GetFirewallManager()
        {
            Type NetFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
            return (INetFwMgr)Activator.CreateInstance(NetFwMgrType);
        }

        private static INetFwOpenPort _GetPort(string title, int portNo, bool isUDP)
        {
            Type type = Type.GetTypeFromProgID(PROGID_OPEN_PORT);
            INetFwOpenPort port = Activator.CreateInstance(type)
                as INetFwOpenPort;

            port.Name = title;
            port.Port = portNo;
            port.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
            port.Protocol = isUDP ? NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP : NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
            port.IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY;

            return port;
        }

        private static bool _SetEnableFirewall(bool enable)
        {
            _fwMgr = _GetFirewallManager();

            _fwMgr.LocalPolicy.CurrentProfile.FirewallEnabled = enable;

            return _fwMgr.LocalPolicy.CurrentProfile.FirewallEnabled;
        }

        #endregion Methods
}

 

 

AddProgram 함수 사용하시면 된다.

다중 스레드를 사용하다보면 자원을 공유하게 되는 상황이 있을 수 있다.

이러한 상황에서 일정 영역을 한 번에 한 스레드만 접근 할 수 있는 영역(Critical Section)

으로 만들어 스레드간의 간섭을 없애기 위해 lock문을 사용하고는 한다.

 

하지만 간혹 lock 영역에서의 작업시간이 길어져 다른 스레드들의 대기 시간이 너무 길어지는 상황이 생길 수 있으며,

스레드간 교착상태인 Dead lock이 발생 할 수도 있으며,  

lock 영역에서 외부 라이브러리를 사용하는 경우(왠만해서는 피해야 하지만;) 해당 라이브러리 오류로 반환이 되지 않고

라이브러리 서브루틴에서 무한 루프라도 돌면 해당 모든 스레드가 대기 상태가 되어 프로그램이 맛이 가버리는 골때리는 상황이 오기도 한다.

 

이럴경우 Monitor.TryEnter (System.Threading.Monitor.TryEnter) 메소드를 사용하여 해결 할 수 있다.

 

다음 예제는 lock으로 인한 스레드들이 대기 시간을 확인해보자.

작업 시간에 5초가 소요되는 함수를 실행하는 예제이다.

 

더보기
namespace threadTest
{
    public partial class Form1 : Form
    {
        
        public Form1()
        {
            InitializeComponent();
            Thread t1 = new Thread(() => DoConsoleWirte(1));
            Thread t2 = new Thread(() => DoConsoleWirte(2));
            Thread t3 = new Thread(() => DoConsoleWirte(3));
            Thread t4 = new Thread(() => DoConsoleWirte(4));
            t1.IsBackground = true;
            t2.IsBackground = true;
            t3.IsBackground = true;
            t4.IsBackground = true;
            t1.Start();
            Thread.Sleep(10);
            t2.Start();
            Thread.Sleep(10);
            t3.Start();
            Thread.Sleep(10);
            t4.Start();
        }
        
        static readonly object lockobj = new object();
        public void DoConsoleWirte(int id)
        {
            Console.WriteLine(id + " : START " + DateTime.Now.ToString("HH:mm:ss.fff"));
            lock(lockobj)
            {
            	Console.WriteLine(id + " : NOW WORKING "  + DateTime.Now.ToString("HH:mm:ss.fff"));
          	Thread.Sleep(5000); //작업시간 5초(5000 ms)
            }
            Console.WriteLine(id + " : WORK DONE "  + DateTime.Now.ToString("HH:mm:ss.fff"));
        }
    }
}
실행결과 
1 : START 17:16:07.439
1 : NOW WORKING 17:16:07.442
2 : START 17:16:07.452
3 : START 17:16:07.467
4 : START 17:16:07.483
1 : WORK DONE 17:16:12.444
2 : NOW WORKING 17:16:12.444
2 : WORK DONE 17:16:17.446
3 : NOW WORKING 17:16:17.446
3 : WORK DONE 17:16:22.451
4 : NOW WORKING 17:16:22.451
4 : WORK DONE 17:16:27.468

 

t1 - t4 총 4개 스레드가 순차적으로 DoConsoleWirte 함수를 실행 할 때 Critical Section에 접근 할 수 있는 스레드는

한 번에 하나이기 때문에 먼저 실행된 t1 스레드 부터 순차적으로 스레드가 실행 및 종료된다.

 

위 테스트 에서는 lock문의 동작을 확인하기 위한 것이기에 작업시간을 5초로 설정 하였지만 Critical Section 에서 무한루프에 빠지게 된다면 t2 , t3 , t4 스레드는 무한 대기상태가 된다.

 

 

Monitor.TryEnter 함수는 다음과 같이 사용한다.

 

더보기
bool lockTaken = false; //단독잠금 설정 여부 True 일 때 해당영역에 접근 가능. False 일때는 대기.
Monitor.TryEnter(lockobj, 2000, ref lockTaken); //대기시간 2초(2000ms) 설정
try
{
	if (lockTaken)
	{
		//작업 
	}
	else
	{
		//시간 초과시 작업        
	}
}
catch(Exception error) { throw error }
finally { if (lockTaken) Monitor.Exit(lockobj); }

 

 

Monitor.TryEnter 를 사용한 예제는 다음과 같다. 작업시간 5초, 대기시간 2초로 설정한 예제이다. 

 

더보기
public partial class Form1 : Form
    {
        
        public Form1()
        {
            InitializeComponent();
            Thread t1 = new Thread(() => DoConsoleWirte(1));
            Thread t2 = new Thread(() => DoConsoleWirte(2));
            Thread t3 = new Thread(() => DoConsoleWirte(3));
            Thread t4 = new Thread(() => DoConsoleWirte(4));
            t1.IsBackground = true;
            t2.IsBackground = true;
            t3.IsBackground = true;
            t4.IsBackground = true;
            t1.Start();
            t2.Start();
            t3.Start();
            t4.Start();
        }
     
        static readonly object lockobj = new object();
        public void DoConsoleWirte(int id)
        {
        	Console.WriteLine(id + " : START " + DateTime.Now.ToString("HH:mm:ss.fff"));
            bool lockTaken = false; //단독잠금 설정 여부 True 일 때 해당영역에 접근 가능. False 일때는 대기.
            Monitor.TryEnter(lockobj, 2000, ref lockTaken); //대기시간 2초(2000ms) 설정
            if (lockTaken)
            {
            	Console.WriteLine(id + " : NOW WORKING "  + DateTime.Now.ToString("HH:mm:ss.fff"));
                Thread.Sleep(5000); //작업시간 5초(5000ms)
            }
            else
            {
                Console.WriteLine(id + " : TIME OVER " + DateTime.Now.ToString("HH:mm:ss.fff"));
                return;
            }
            Console.WriteLine(id + " : WORK DONE " + DateTime.Now.ToString("HH:mm:ss.fff"));
        }
    }
실행결과
1 : START 17:26:37.527
1 : NOW WORKING 17:26:37.530
2 : START 17:26:37.558
3 : START 17:26:37.564
4 : START 17:26:37.582
2 : TIME OVER 17:26:39.569
3 : TIME OVER 17:26:39.569
4 : TIME OVER 17:26:39.599
1 : WORK DONE 17:26:42.531

 

t1 스레드가 작업을 시작하고 t2 , t3 , t4 스레드는 대기상태에 들어간다. 

설정된 2초가 지난 뒤에도 t1 스레드가 해당 Critical Section을 점유하고 잠금상태에 있기 때문에 

t2 , t3 , t4 스레드는 TIME OVER 메세지를 표시하고 작업을 끝마치는 모습을 볼 수 있다.

 

 

위 예제에서는 try catch 문을 사용하지 않았지만, 일부 상황에서 잠금이 해제되지 않을 수 있기 때문에 꼭! 꼮!! try catch finally 사용하시길 바란다.

최단 작업 우선 스케줄링(Shortest Job First Scheduling)은 평균 대기 시간을 최소화하기 위해 CPU 점유 시간이 가장 짧은 프로세스에 CPU를 먼저 할당하는 방식의 CPU 스케줄링 알고리즘으로 평균 대기시간을 최소로 만드는 걸 최적으로 두고 있는 알고리즘이다.

 

FIFO 스케줄링과 SJF 스케줄링의 차이점은 

 

장점

-   항상 실행 시간이 짧은 작업을 신속하게 실행하므로 평균 대기 시간이 가장 짧다.

 

단점

-   초기의 긴 작업을 짧은 작업을 종료 할 때까지 대기시켜 기아가 발생한다.

-   기본적으로 짧은 작업이 항상 실행되도록 설정하므로 불공정한 작업을 실행한다.

-   실행 시간을 예측하기 어려워 실용적이지 못하다.

 

스케줄링 실행

반환시간 = 마지막 작업 시작시간 - 이미 처리한 시간 - 도착시간

SJF 스케줄링은 프로세스 작업을 시작하면 해당 프로세스 작업완료까지 다른 프로세스의 작업을 시작하지 않는다.

그러므로 반환시간 계산식의 이미 처리한 시간이 존재 할 수가 없으니

반환시간 = 마지막 작업 시작시간 - 도착시간이 된다. 

 

예제)

도착시간 0 1 3 5 9
프로세스 A B C D E
CPU사이클 8 5 2 4 3

프로세스별 도착시간과 필요한 CPU사이클(작업시간) 이 위와 같을 때 프로세스의 실행 순서는 다음과 같다.

시간() 실행중인 프로세스
(괄호는 남은시간)
실행대기
(괄호는 CPU 사이클())
설명
0 A(8)   가장먼저 도착한 A실행
1 A(7) B(5) B도착
2 A(6) B(5)  
3 A(5) B(5), C(2) C도착
4 A(4) B(5), C(2)  
5 A(3) B(5), C(2) ,D(4) D도착
6 A(2) B(5), C(2) ,D(4)  
7 A(1) B(5), C(2) ,D(4)  
8 C(2) B(5) A종료, 사이클이 가장짧은 C실행
9 C(1) B(5),E(3) E도착
10 D(4) B(5),E(3) C종료, 사이클이 가장짧은 D실행
11 D(3) B(5),E(3)  
12 D(2) B(5),E(3)  
13 D(1) B(5),E(3)  
14 E(3) B(5) D종료, 사이클이 가장짧은 E실행
15 E(2) B(5)  
16 E(1) B(5)  
17 B(5)    

:

22 B(0)   모든작업 완료.

실행순서 = A(0초) -> C(8초) -> D(4초) -> E(14초) ->B(17초)

대기시간

A B C D E 평균
0 17 - 1 = 16 8 - 3 = 5 10 - 5 = 5 14 - 9 = 5 (0+16+5+5+5) / 5 = 6.2

[응시자격]

<관련학과>

4년제 졸업 / 졸업 예정자

3년제 졸업 후 관련업계 실무경력 1년

2년제 졸업 후 관련업계 실무경력 2년

학점은행제 106학점 이상 취득

 

<기술자격 소지자(동일 및 유사 직무분야)>

산업기사 취득 후 관련업계 실무경력 1년
기능사 취득 후 관련업계 실무경력 3년
동일 및 유사 직무분야의 다른 종목 기사 등급 이상의 자격 취득자

 

<기타>

기술훈련과정 이수자(기사수준)
기술훈련과정 이수자(산업기사수준) 이수 후 관련업계 실무경력 2년
관련업계 실무경력 4년 

 

자세한 내용은 아래 홈페이지 참조.

http://www.kric.go.kr/jsp/board/portal/sub04/lic/certifiDetail.jsp?board_seq=52

+ Recent posts