728x90

http://blog.naver.com/zacronan?Redirect=Log&logNo=40018174412
http://airtight.yonsei.ac.kr/research/COM/thread_apartment.htm

1-2 스레딩 모델 

먼저 이 부분을 설명하기 위해서는 아파트먼트(Apartment)라는 것에 대해 설명이 필요하다. 아파트먼트는 하나의 프로세스 내에서 여러 개의 스레드를 가지고 각각의 스레드 동기화 문제를 해결하기 위해 나온 것으로 각 오브젝트를 가지고 있는 하나의 방이라는 개념으로 이해하면 된다. 각 아파트먼트당 하나의 스레드가 존재하며 오브젝트는 적당한 아파트먼트 안으로 들어가게 된다. 

이러한 스레딩 모델(Threading Model)은 레지스트리에서 CLSID의 스레딩 모델의 값을 보면 된다. 가능한 경우는 스레딩 모델이 아예 없거나 아파트먼트, 프리(Free), 보스(Both)가 되는 것이다. 아파트먼트는 STA 모델을 가리키며 프리는 MTA 모델을, 보스는 STA, MTA 둘 다 지원한다는 것을 말한다. 이 값이 아예 없다는 것은 main STA에서 동작한다는 것을 말하고 이 main STA는 프로세스가 초기에 주 스레드에서 호출한 CoInitializeEx 값에 의해 결정된다. 




① STA(Single Threaded Apartment) 

STA 내에서 서버는 각각의 아파트먼트 내에 각 오브젝트가 존재하며 하나의 프로세스 내에서 각 아파트먼트 내에 각 오브젝트가 들어가 있게 된다. 이 경우는 CoInitializeEx(NULL,COINIT_APARTMENTTHREADED)를 각각의 스레드당 호출하여 초기화 된다. 이러한 각각의 오브젝트 호출은 메시지에 의해 동기화 된다. 즉 이러한 메시지를 통해 동기화 된다는 것은 메시지 루프를 가져야 한다는 얘기이다. 

하나의 아파트먼트 내에서는 프록시의 개입 없이 직접적으로 호출할 수 있으나 다른 아파트먼트 내에서는 이렇게 될 수는 없다. 즉 하나의 메소드 호출은 클래스 네임이 OleMainThreadWndClass를 가지는 윈도우 클래스가 등록한 WndProc로 가서 적당한 Interface의 메소드를 호출하게 된다. 이러한 모델 내에서의 호출은 그림 5와 같다. 










그림 5 : STA에서의 메시지 큐 


그림 5에서 보는 것처럼 서버로의 모든 호출은 큐(Queue) 속에서 들어가며 GetMessage,DispatchMessage에 의해 해당 오브젝트로 전달된다. 




② .MTA(Multi Threaded Apartment) 

MTA 내에서 하나의 아파트먼트 내에 여러 개의 스레드와 오브젝트가 들어가게 되며 따라서 오직 한 번만 CoInitializeEx(NULL, COINIT_MULTITHREADED)를 호출하면 된다. 이 경우에는 여러 개의 스레드가 동시에 오브젝트의 메소드로 접근할 수 있기 때문에 Reentrant하도록 소스가 작성되거나 동기화 문제를 코드 안에서 해결해야 한다. 하지만 서버 안에서의 스레드간 인터페이스 전달에 프록시가 개입할 필요가 없다. 

또한 STA로 작성하는 것보다 빠른 속도를 보이는 멀티 스레드의 장점을 충분히 활용할 수 

가 있으며 하나의 프로세스 내에 오직 하나의 MTA만 만들어질 수 있다. 




③ 혼합 모델 

이 모델은 프로세스가 한 개의 MTA와 한 개 이상의 STA를 가진다는 것을 의미한다. 




④ STA와 MTA와 혼합 모델에서의 선택 

어떤 오브젝트의 모델을 선택하는 것은 각기 장단점이 존재하기 때문에 상황에 맞게 선택해야 하는데, STA에서는 프로그래머가 스레드간의 동기화를 신경쓸 필요가 없다. 그러나 여기서 다른 아파트먼트로 인터페이스를 전달하기 위해서는 프록시의 개입을 필요로 하므로 느려질 수 있으며, 또한 객체로의 메소드 호출이 메시지 루프(Loop)를 통해 한번에 하나씩 만 처리되기 때문에 멀티 스레드의 장점을 충분히 활용할 수가 없게 된다. 

그러나 MTA를 선택한 경우 서버 객체의 구현자는 여러 개의 스레드가 동시에 메소드 호출을 수행할 수가 있으므로 코드는 Reentrant하게 작성되거나 Mutex, Critical Section, Event를 통해 동기화 코드를 작성해야 한다. 따라서 작성이 어려워지게 되지만 이 경우라고 해도 수많은 사용자가 사용할 수 있는 오브젝트라면 한번 고려해볼 만하다.


출처 : http://broneri.tistory.com/372

728x90
728x90

struct _tagPoint{
     int x; 
     int y;
};

POINTS는 선언되지 않은 심볼이므로 struct _tagPoint POINTS;라고 하면,

POINTS라는 이름의 구조체 변수가 생성됩니다.

당연히 POINTS는 타입으로 선언된 것이 아니므로 POINTS s;라는 구문은 오류입니다.

struct의 임무는 뒤에 나오는 식별자 _tagPoint가

구조체 태그이름임을 나타내는 지시어입니다.

이는 C와의 하위 호환성을 위해 남겨둔 것으로,

C++에서는 선택적으로 사용해도 되고, 사용하지 않아도 상관 없습니다.

C에서 변수선언은 기본적으로

"변수 선언이 가능한 키워드로 시작"될 때만

변수 선언으로 인식하도록 되어 있는 구조입니다.

따라서 한 문장의 시작이 int, char, void 등의 타입을 나타내는

'키워드'여야만 유효한 선언으로 간주하는 구조로 설계되었습니다.

enum이나 union, struct등의 사용자 정의 타입은

그냥 선언한 이름만 쓰면 변수 선언으로 인식하지 못하는 구조이죠.

그래서 해당 타입이 무엇으로 선언되어 있는지를

컴파일러에게 알려주도록 C언어는 설계되었습니다.


 

하지만 C의 슈퍼셋으로 설계된 C++은

사용자 정의 타입 역시 기본 데이터 타입과 통합된 타입 시스템으로 관리하므로,

더이상 사용자 정의 타입의 변수를 생성할 때 그 종류를 알려줄 필요가 없지만,

C와의 하위 호환성을 위해 남겨둔 것 뿐입니다.

C에서 사용자 정의 데이터 타입의 변수를 선언하려면

사용자 정의 타입임을 나타내는 키워드(enum, struct, union 등)와

선언된 타입의 태그 이름을 같이 적어 주어야 했습니다.

하지만 매번 struct를 써주는 것도 번거로운 일이므로,

C에서는 사용자 정의 타입 이름도 typedef 로 재정의 가능하도록 허용했습니다.

그래서 C에서는 사용상의 편의를 위해서 구조체 선언과 동시에

구조체의 태그 이름으로 별 의미없는, 잘 안쓰는 이름을 붙이고

typedef 이름을 잘 쓰이고 읽기 쉬운 이름으로 붙이는 관습이 생겨난 것입니다.

C에서

struct POINTS
{
    int x, y;
};

POINTS s;

라고 변수를 정의하면, 컴파일 에러를 냅니다.

이는 POINTS가 타입이름으로 선언된 이름이 아니라,

사용자 정의 타입의 태그 이름으로만 선언된 이름이기 때문이죠.

태그이름과 타입이름은 엄연히 다른 것이니까요.

하지만 C++ 에서 위의 코드는 아무런 문제가 없습니다.

C++의 타입 시스템은 사용자정의 타입도 기본 데이터 타입과 마찬가지로 취급하므로

구조체 태그 이름을 선언하는 순간, 그 이름이 타입 시스템 내에서

유효한 타입이름으로 등록되어 사용할 수 있게 되므로, C++에서는 사실상

typedef로 타입을 선언하나, 그냥 struct만으로 선언하나 아무런 차이가 없습니다.

단, 여기서 주의할 점은, 다음과 같은 구문에서,

typedef struct
{
    int x, y;
} POINTS;

이와 같은 구문은 컴파일러는 이렇게 해석합니다.

a. 이름없는 구조체를 만들고,

b. 여기에 두 멤버변수 x,y를 추가하고

c. 이 이름없는 구조체의 타입이름을 POINTS로 재정의한다.

여기서 문제가 되는 것은 '이름없는 구조체'를 만드는 것이

컴파일러에 따라 지원될 수도 있고, 안될 수도 있다는 것이죠.

'이름없는 구조체'는 언어 표준에서 명시된 것이 아니므로,

이를 지원하는 컴파일러는 살짝 표준에서 빗겨나가 있긴 하지만

대부분의 컴파일러가 지원하는 기능이므로 대부분 저렇게 쓰기도 합니다.

하지만, 진짜 언어 표준만을 지원하는 컴파일러는

위와 같은 구문은 컴파일시 에러나 워닝을 냅니다.

그래서 그와 같은 컴파일러에서는 구조체를 typedef로 새 타입이름으로 선언하더라도,

임시로 사용할 태그 이름이 필요하게 됩니다.

따라서, 이와 같은 컴파일러에서는 다음과 같이 임시 태그 이름을 사용하여

typedef로 타입 이름을 선언해야 합니다. 

(물론, 번거롭긴 하지만 표준과 일치하는 방법입니다.)

typedef struct _tagPoint{
     int x; 
     int y;
}POINT;

이와 같은 구문은, 어떤 컴파일러를 쓰더라도 정확히 동일한 결과를 내므로

안전한 기법이라고 할 수 있겠습니다.

POINTS라는 이름이 끝에 온다면,

이는 typedef 타입 이름으로 간주되 POINTS라는 이름이 struct 뒤에 바로 온다면

구조체 태그 이름으로 간주된다는 차이가 있습니다.

즉, 첫번째 예제의 POINTS는 typedef 타입 이름이 되며,

두번째 예제의 POINTS는 구조체 태그 이름이 됩니다.

반면, 세번째 예제에서는 typedef구문인데,  POINTS는 구조체 태그 이름만 있고

typedef로 선언할 새 타입 이름이 없으므로 오류입니다.

typedef의 기본 구문은,

typedef (기존타입) (새타입이름);

과 같은 형식입니다.

typedef struct POINT{
     int x; 
     int y;
};

와 같이 쓴다면, struct POINT { ... } 이 부분은 (기존타입)에 해당하지만,

(새타입이름)에 해당하는 부분이 없으므로 컴파일러는 typedef 부분을 무시하고

그냥 POINT라틑 태그이름으로 구조체를 선언하게 되는 것입니다.


728x90
728x90

쉽게 말해 enum 은 열거형 변수 입니다.

"어떻게" 생각하면 struct와 다르냐? 라고 물을 수 있지만.

"전혀" 다릅니다.

 

보통 enum은 상수를 정의하는데에 많이 쓰입니다.

소스의 가독성을 높인다거나 상수에 의미를 부여해서 쓸 수 있습니다.

 

전처리기인 #define 을 사용하거나, 전역 변수를 const로 선언해서 상수처럼 사용이 가능하지만

enum을 상수로 생각해서 처리할때의 이점이 있습니다. (뒷부분에 설명하겠습니다.)

 

우선 이넘(enum)을 선언하는 방법은 다음과 같습니다.

 

enum {mon, tue, wed, thr, fri, sat, sun } day;

 

여기서 day를 열거형 변수라 하고 그 하위의 항목(원소) 들 ( mon, tue, wed, thr, fri, sat, sun)로 구성됩니다.

 

특별하게 값을 지정하지 않는다면 enum의 각 원소들은 순차적인 "정수" 값을 갖게 됩니다.

이때 갖게되는 값은 mon부터 0, 1, 2 ... 6 까지 각 각 가지게 됩니다.

 

특별하게 값을 지정해서 enum을 사용한다면

 

enum {mon=100, tue, wed=200, thr, fri=300, sat, sun } day;

 

이렇게 선언을 하게 되면, mon은 당연히 100일거고,, tue는... 150일까요?

tue는 101을 갖게 됩니다.

 

enum의 값을 정하는 정의는 "이전 원소 값의 + 1" 입니다.

 

 

그럼. "왜 이넘을 사용해야 하는가.." 입니다.

 

사실 enum은 필요없을 지도 모릅니다.

#define 이 있고,

const int 가 있습니다.

 

하지만 C++ 이 enum에게 준 몇가지의 특별한 이유 때문에 enum을 사용합니다.

 

① 기억이 용이하다.

enum대신 정수형 변수를 대신 사용할 수 도 있습니다. 하지만, 이렇게 될때 각 정수의 의미가 무엇인지를 만드는 사람이 기억하고 있어야 하죠. 값이 많아질 수록 혼란스러울겁니다. 보통, 사람은 숫자보다 문자를 더 잘 기억합니다. 그리고, enum의 원소들을에게 의미를 부여한 이름을 준다면 더 기억하기가 쉽겠죠..

 

② 소스의 가독성(Readability)이 높아진다.

enum의 원소만 봄으로써, 그 상수의 의미를 보다 쉽게 파악 할 수 있고, 소스 전체의 가독성을 높이는데 도움이 됩니다. 예를 들어 whatdays = 0; 이라고 표현한다면, 이게 월요일인지,, 일요일인지, 도무지 알 길이 없습니다. 하지만 whatdays = mon; 이라고 한다면, 두말할나위없이 이해할 수 있겠죠. 두명이상의 Project나 팀단위 작업을 할때에는 알고리즘을 아무리 잘 짜도 소스가 X같으면, 프로젝트 진행이 어려워집니다. 따라서 이런 팀단위 작업에는 가독성이 아주 중요시 됩니다.

 

③ 안전하다.

앞서 예를든 days에 대입될수 있는 값은 7개중 하나로 제한이 되기때문에 사용자의 실수를 컴파일러가 미리 예방해줄 수 있습니다. 따라서 변수형을 사용하는것보다 안전하죠.

 

 

필수는 아니지만 있으면 좋다. 이게 이넘(emum)입니다.

 

 

enum을 보다 효율적으로 사용하는 방법은

 

typedef를 사용하는겁니다.

 

바로 예부터 보자면...

 

typedef enum CDays {enum {mon, tue, wed, thr, fri, sat, sun };

 

이제 CDays는 하나의 타입으로 생성된겁니다.

 

CDays WhatDay(); 와 같이 오늘이 몇요일인지 리턴하는 함수를 작성 할 수도 있구요.

 

CDays Day = WhatDay();

 

와 같이 Enum을 효과적으로 처리할 변수를 만들어 사용할 수 있습니다.

[출처] enum 사용법|작성자 다람쥐


enum 사용 예제 입니다. 

  1. #include <stdio.h>  
  2. enum week {sun, mon, tue, wed, thu, fri, sat};  
  3. int main(void)  
  4. {  
  5.     enum week day1;  
  6.     day1=fri;  
  7.     printf("day1 : %d\n", day1);  
  8.     printf("fri : %d\n", fri);  
  9.     day1=mon;  
  10.     printf("day1 : %d\n", day1);  
  11.     printf("mon : %d\n", mon);  
  12.     return 0;  
  13. }  


// 실행 결과


출처 : http://kimgagakk.tistory.com/341

728x90

+ Recent posts