CLOSE SEARCH
POSTS TAGGED WITH: C#

Thread in C#

멀티태스킹과 프로세스, 스레드

멀티태스킹은 윈도우가 지원하는 많은 기능 중 하나로 동시에 여러개의 프로그램들이 실행될 수 있도록 해준다. 이때, 실행중인 프로그램들은 프로세스로 관리된다. 프로세스가 실행된 후에는 운영체제에서 자동적으로 멀티태스킹을 지원해 준다. 하나의 프로세스는 기본적으로 하나의 스레드를 가지며 필요한 경우 다수의 스레드를 가질 수 있다. 스레드는 프로세스 내에서 실행되는 하나의 함수로 이해해도 좋다. 일반적으로 프로세스는 특정 시점에 하나의 함수(메인스레드)만을 수행하지만 스레드를 통해 다수의 함수를 동시에 실행할 수 있다.

동시에 여러개의 함수가 실행될 경우 이들의 실행순서와 동기화에 신경을 써야한다.

 

스레드의 상태

스레드는 아래와 같은 4가지 상태를 갖는다.

  • Unstarted : 스레드가 생성되었지만 아직 실행되기 전
  • Runnable : 스레드 생성 후 Start() 를 호출하면 Runnable 상태가 되며 CLR에 의해 큐(실행 큐) 형태로 관리된다. 그 후 시스템에 의해 우선순위에 따라 실행된다. 오직 실행큐에 있는 스레드만이 CPU 사용권한을 가진다. 
  • Suspended : 실행중인 스레드에서 Suspend()나 Sleep() 함수를 호출할 경우 해당 스레드는 실행 큐에서 대기 큐로 이동되며 CPU 사용 권한을 상실한다. Resume() 함수를 호출하거나 지정된 대기 시간이 지나면 다시 Runnable 상태가 될 수 있다. 
  • Stopped : 스레드가 실행을 마친 후에 리턴되거나 실행중 Abort()를 호출한 경우
스레드의 현재 상태를 알아보기 위해서는 Thread 클래스의 ThreadState 속성을 얻는다. 이 속성은 아래와 같은 값들을 가질 수 있다.
  • Unstarted
  • Running
  • WaitSleepJoin
  • SuspendRequest
  • Suspended
  • AbortRequested
  • Stopped
스레드의 상태를 조작하는데 사용되는 함수는 다음과 같다.
  • public void Start() : 스레드를 시작한다.
  • public bool Join(int millisecondsTimeout) : 스레드가 종료되기까지 대기한다.
  • public void Suspend() : 스레드를 대기상태로 변경한다.
  • public void Resume() : 스레드를 재시작한다. 
  • public static void Sleep(int millisecondsTimeout) : 지정된 시간만큼 대기한다. 
  • public void Abort() : 스레드를 종료한다. 

Assertion in C#

Assertion은 특정 조건이 만족되지 않을때 프로그램을 멈추고 오류를 표시해주는 기능이다.  Assertion 관련 함수들은 첫번째 파라미터로 검사할 조건식을 받는데, 이 조건식이 true이면 다음 작업을 계속 진행하고 false이면 프로그램을 종료시키고 스택정보나 지정한 오류정보를 표시한다.

  • Debug.Assert() : 디버그 모드에서만 동작한다. 
  • Trace.Assert() : 디버그 모드와 릴리즈 모드에서 모두 동작한다. 

DllImport – C#에서 C, C++로 작성된 DLL 사용하기

DllImport 어트리뷰트는 C#에서 C나 C++로 작성된 DLL을 사용할 수 있도록 해준다. 반드시 System.Runtime.InteropServices를 사용하도록 지시해 주어야 한다.

User32.dll 파일을 임포트해서 MessageBox 함수를 호출하는 방법은 아래와 같다.

Obsolete

Obsolete는 C#에서 제공하는 내장 어트리뷰트 중 하나로, 클래스에서 더이상 사용되지 않는 함수를 표시하는 역할을 한다. 이렇게 Obsolete 어트리뷰트로 속성된 함수를 사용하게 되면 컴파일러는 지정된 경고 메시지를 표시한다.

5번 라인에서 oldMethod를 Obsolete로 표시하고 있다. 위의 예제를 실행하면 두개의 메소드 모두 호출되지만  비주얼스튜디오 상의 오류 목록을 보면 아래와 같이 지정된 경고 메시지가 표시되는 것을 볼 수 있다.

Conditional

Conditional 어트리뷰트는 C#에서 제공하는 내장 어트리뷰트 중 하나로 전처리 지시어의 정의여부에 따라 호출되는 조건부 함수를 정의할 때 사용한다.

Conditional 어트리뷰트를 사용하기 위해서는 System.Diagnostics를 사용하도록 지시해야한다. (라인 4)

Conditional 어트리뷰트는 함수 정의 바로 윗 부분에서 [Conditional(“전처리지시어”)]와 같은 형식으로 사용된다. (라인 8, 14) 위의 예제에서는 1번 라인에서 KEI라는 전처리 지시어를 정의했기 때문에 이에 해당하는 어트리뷰트를 가지고 있는 ConditionalMethod1 함수만 호출되고, ConditionalMethod2 함수는 명시적으로 호출을 한다고 해도 컴파일러에 의해 유효하지 않은 함수로 판단되어 호출되지 않는다.

Conditional 어트리뷰트가 적용되는 함수는 반드시 리턴형이 void이어야 하며, 인터페이스의 멤버함수에서는 사용할 수 없다.

C#에서의 객체 비교

C#에서는 두가지 방식으로 객체를 비교한다. 

  • 참조 비교 : 객체의 참조 값이 같은지 비교. 즉 같은 메모리를 가리키고 있는지 비교
  • 값 비교 : 객체가 가지고 있는 값을 비교
이러한 비교는 기본적으로 최상위 클래스인 Object의 Equals(virtual)를 통해 이루어진다. Equals는 기본적으로 참조비교를 수행하지만 하위클래스에서 재정의되어 다양한 형태의 비교를 수행하게 된다. 또한 ReferenceEquals 정적함수를 통해서 참조비교를 수행할 수도 있다.
Equals는 가상함수이기 때문에 새로운 클래스를 생성할때 해당 클래스에 적합하게 동작하도록 아래와 같은 형태로 재정의 해야 한다.

이렇게 Equals를 재정의하게 되면 기본적인 참조비교가 수행되지 않고 사용자가 정의한 비교코드가 수행된다. 이러한 재정의 작업을 수행할때 부가적으로 GetHashCode 함수도 재정의해 주어야 한다.  그렇지 않으면 Object.GetHashCode()를 재정의하지 않았다는 경고가 발생하게 된다.

Exception in C#

프로그램 실행도중 발생한 오류를 처리하고, 이 오류에 의해서 프로그램이 비정상적으로 종료되는 것을 방지하기 위해서 예외처리 기능을 사용하며 C# 에서는 Exception 클래스를 통해 이 기능을 제공한다.

C#의 모든 예외 클래스들은 SystemException 클래스와 ApplicationException 클래스로부터 파생되는데 전자의 경우 CLR에 의해 발생된 예외에 대한 클래스들이 상속을 받으며, 후자의 경우 개발자가 직접 작성한 예외 클래스가 상속을 받는다.

예외처리는 try..catch 구문을 통해 이루어진다. 기본적인 구조는 아래와 같다.

①번 구역에는 예외가 발생될 것으로 예상되는 코드를 작성한다. 만약 ①에 포함된 코드에서 에외가 발생한다면 catch { } 사이의 코드(②)가 수행이 된다. 이 부분에는 주로 발생된 예외에 대한 처리코드가 들어간다. try{}와 catch{}는 필수 요소이며 두 요소의 순서가 바뀌면 안된다. catch {}는 필요한 수 만큼 작성될 수 있다. finally{}의 경우 예외 발생 유무에 상관없이 항상 실행된다.

문자열 in C#

C#에서 문자열은 System.String 클래스의 객체이며 C, C++과 마찬가지로 따옴표(“) 사이에 포함된 문자들의 집합이다. +연산자를 통해 다른 문자열이나 문자와 연결하고, @를 사용해서 이스케이프 문자도 그대로 출력할 수 있는 기능을 제공한다.

Object 클래스에 있는 Equals() 함수는 기본적으로 객체의 참조값을 비교하지만 String 클래스의 Equals() 함수는 문자열 값을 비교하도록 오버라이딩 되어 있다. 또한 == 연산자 오버로딩을 통해서도 문자열 값을 비교한다.

string은 불변객체이다. 다시말하면 한번 생성되면 자신이 가지고 있는 문자열을 변경할 수 없다. 외부적으로는 동일한 객체를 사용하는 것처럼 보이지만 내부적으로는 새로운 객체를 생성한다. C#에서는 이런한 불변(Immutable) 문자열 객체의 단점을 보완하기 위해 Java의 StringBuffer나 Objective-C NSMutableString와 같이 자신이 가지고 있는 문자열을 수정할 수 있는 StringBuilder 클래스를 제공한다.

string의 경우 문자열이 변경될 때마다 새로운 객체가 생성되기 때문에 단시간에 많은 변경이 발생하게 될 경우 비효율적이다. 그러므로 변경이 잦은 문자열은 StringBuilder를 통해 생성하는 것이 좋다.

foreach in C#

foreach 반복문은 배열 객체나 컬렉션 객체의 각 요소에 접근하는 편리한 방법을 제공하는 반복문이다. 전통적인 for문의 경우 제어변수와 반복횟수 등을 사용하지만 foreach문은 대상이 되는 배열 혹은 컬렉션 객체와 요소 접근에 사용할 변수(반복 변수)를 사용한다. 반복변수는 읽기전용이므로 foreach 내부에서 반복변수에 값을 할당하거나 수정할 수 없다.

foreach문에서 반복변수는 해당 반복회차의 데이터를 나타낸다. 즉, foreach문은 배열이나 컬렉션 객체를 첫 요소부터 마지막 요소까지 반복하면서 각 반복회차에 해당되는 요소값을 반복변수를 통해 제공한다.

다차원 배열의 경우 foreach문은 메모리에 저장된 순서대로 반복을 진행한다.