출처 : http://wangmul.egloos.com/1566763

 

싱글턴패턴의 남용

어디서나 접근 가능하다는 장점은 프로그래밍에서 큰 잇점을 주게 된다.
가장 일반적으로 이용할 수 있는 것은 프로그램 전체적으로 영향을 주는 설정값들 ( 게임서버의 전체/현재 접속자 수, 현재 실행되어 있는 곳의IP등)을 위치에 관계없이 접근할 수 있다는 것은 그 누구도 부정할 수 없는 멋진 장점이다.

하지만 여기에서부터 문제는 발생한다.
어디서나 접근이 가능하기에 각종 매니저 클레스(주1)를 싱글턴으로 사용하게 된다. 매니저를 싱글턴으로 사용하는 방식 자체에 문제가 있다고 볼수는 없다. 코드를 파악하기도 편하고 새로운 기능을 만들어 넣을때도 쉽게 만들어 넣을 수 있다. 그러나매니저클래스를 싱글턴으로 사용하기 시작하면 로직은 흐트러질 수 밖에없다.

싱글턴이 흐트러뜨리는 로직

매니저클래스에서 로직을 사용하게 되었을 때 문제를 발생시키는 것은 싱글쓰레드일 때보다 멀티 쓰레드일때 문제가 더 크게 발생한다.

void A클레스::유저정보조회 ( 유저아이디 )
{
    if ( DB.유저정보조회 (유저아이디) == false )
    {
        세션관리자.GetInstance().세션삭제 (유저아이디)
    }
}

void B클레스::패킷처리 ( 패킷데이터 )
{
    파싱완료데이터 = 패킷파싱 (패킷데이터 )
    switch ( 파싱완료데이터.패킷타입가져오기() )
    {
    case 로그인 :
        ...
        break;
    case 로그아웃 :
        세션관리자.GetInstance().세션삭제 (유저아이디)
        break;
    }
}

멀티 쓰레드에서 이런식으로 많은 곳에서 세션삭제를 요청하게 된다면 세션삭제에 대한 흐름이 흐트러져 여러곳에서 세션 삭제를 동시에 요청할 수도있다. 그리고 더욱 문제가 되는 것은 세션 삭제에서 오류가 발생했을 때 세션 삭제요청이 어디서 왜 호출되었는지 알기 어려워진다. 그렇기때문에세션 삭제에 대해서 중복 삭제 요청에 대한 추가적인 처리가 들어가야 하고 삭제안에서 여러가지 조건을 검사해 줘야 한다.

싱글턴을 사용하지 않는다면

그렇다면 싱글턴을 사용하지 않는다면 어떻게 바뀔까?
일단, 세션관리자를 마음껏 호출할 수 없기 때문에 위의 두 메소드는 다른 방식으로 만들어져야 한다.

bool A클레스::유저정보조회 ( 유저아이디 )
{
    if ( DB.유저정보조회 (유저아이디) == false )
    {
        return false;
    }
}

파싱완료데이터 B클레스::패킷처리 ( 패킷데이터 )
{
    파싱완료데이터 = 패킷파싱 (패킷데이터 )
    return 파싱완료데이터
}

이렇게 바꾼 뒤에 메인쓰레드에서 다음과같이 확인을 하는 식으로 변경한다.

메인스레드()
{
    패킷 = 패킷수신()
    파싱완료데이터 = 패킷처리 ( 패킷 )
    switch ( 파싱완료데이터.패킷타입가져오기() )
    {
    case 로그인:
    {
        if ( A클레스.유저정보조회( 아이디 ) == true )
        {
            ...
        }
        else
        {
           세션관리자.GetInstance().세션삭제( 아이디 )
        }
    }
    break;
    case 로그아웃:
        세션관리자.GetInstance().세션삭제( 아이다 )
    break;
    }
}

위의 코드로 바뀌면서 얻을 수 있는 것은 예측가능한 코딩을 할 수 있다는 것이다.
세션관리자를 호출할 수 있는 곳은 메인쓰레드뿐이고 그렇기에 세션을 삭제하려면 모든 로직이 메인쓰레드로 들어와야 한다.
세션삭제가 이루어지는 곳이 명확해지기 때문에 오류가 발생할 가능성도 적어지고 로직이 하나의 흐름을 가질 수 있게 된다.

싱글턴은 전역 설정값을 저장할 때만

싱글턴 패턴은 데이터에만 사용되어야 하고 로직에 사용되어선 안된다는것은 내가 가지고 있는 프로그래밍 법칙중에 하나이다. 전역적으로 접근이필요하고 변화가 적은 데이터를 저장하고 접근할 때에만 싱글턴을 사용한다면 그것은 큰 힘이 되어 줄 수 있다.
하지만 어디서든 접근이 가능하다는 것을 로직에까지 이용하는 것은 goto문과 비슷한 문제를 만들어낸다.  갑자기 점프해버리기 때문에코드의 가독성을 해치고 예측 불가능한 호출을 만들어낸다.

솔직하게 고백하면 나 역시도 실무에서 싱글턴의 유혹에 벗어나지 못하곤 한다. 싱글턴의 마약같은 매력에서 벗어나지 못하고 정말 힘들고 어려울 때에싱글턴을 선택하곤 한다.

하지만 한가지만은 분명하게 기억하고 있다. 싱글턴은 프로그래머에게 양날의 검이다.
이 양날의 검은 편하기에 자꾸 쓰고 싶어지게 하지만 함부로 사용하게 되면 자신을 상하게 만든다.
싱글턴을 사용하고 싶다는 생각이 들 때 정말 써야만 하는 것인지 한번 더 고민하고 생각한 뒤에 사용하는 것 만으로도 앞으로 생겨나게 될 큰문제들을 피해갈 수 있는 훨씬 빠른 지름길을 찾는 것이라는 것. 이 사실만 잊지 않는다면 난 언젠가 싱글턴의 유혹에서 벗어날 수 있을 것이라고 생각한다.


-- 아래의 용어들은 제가 임의로 정의한 용어들입니다. --
(주1) 매니저 클래스라는 것은 접속되어 있는 유저들의 세션을 관리하거나 게임방들을 관리하는 것과 같이 공통의 성격을 가지고 있는 인스턴스를관리해주는 클레스로 어디서든 매니저 클래스를 불러와 조건을 넣어주면 조건에 맞는 클래스를 리턴해주는 클래스를 말한다. 일반적으로 아래와 같은모습을 가지고 있다.

세션 세션관리자.GetSession ( 유저아이디 )
{
    ...
    if ( 유저아이디=세션에 저장된 아이디 )
        return 세션
    return NULL
}

 

'Development > 패턴자료' 카테고리의 다른 글

[펌] Some Background on Design Patterns  (0) 2011.08.13
[펌] Creational Patterns  (0) 2011.08.13
[펌] Behavioral Patterns  (0) 2011.08.13
[펌] AbstractFactory  (0) 2011.08.13
[펌] 디자인패턴이란?  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

출처 : http://blog.naver.com/source_jy/50085125989

 

1. EAX(Extended Accumulator X)

a. 누산기인 EAX 레지스터는 입출력과 거의 모든 산술연산에 사용된다.

b. 곱셈과 나눗셈, 변환 명령어 등은 반드시 EAX 레지스터를 필요하게 된다.

c. EAX 레지스터는 32bit 레지스터이고 16bit 레지스터로 ax 가 있다.

d. 누산기로 불리며, 메모리 산술 연산 결과가 저장되는 레지스터

e. 함수 리턴값에 사용

f. Win32 API 함수들은 모두 리턴값을 EAX에 저장한 후 리턴

 

2. EBX(Extended Base X)

a. 주소 지정을 확장하기 위해 인덱스로 사용되는 레지스터

 

3. ECX(Extended Counter X)

a. ECX는 루프의 반복 횟수나 좌우방향의 시프트 비트 수를 기억한다. 그 외에 계산에도 사용된다.

b. ECX는 32bit 레지스터이고 16bit로는 cx가 있다.

c. 카운터로 루프가 반복되는 횟수를 제어하는데 사용되는 레지스터

d. 반복문 명령어에서 참조 카운트로 사용

e. 루프 돌 때 마다 ECX를 1씩 감소

 

4. EDX(Extended Data X)

a. EDX 몇몇 입출력 동작에서 사용된다.

b. 입출력 연산에서 사용되는 데이터 레지스터

 

5. ESP(Extended Stack Pointer)

a. Intel 80386 이상의 마이크로프로세서에는 스택 최상위 주소를 저장하는 스택 포인터라는 ESP레지스터가 있다.

b. ESP 레지스터는 최상위 주소를 저장한다.

c. 프로그램 안에서 수시로 변경된다.

d. 스택에 저장된 변수, 파라메테에 접근 하고자 할 때 ESP 값을 기준으로 하면 프로그램을 만들기 힘들고, CPU가 정확한 위치를 참고할 때 어려움이 있다.

e. 스택의 맨 윗 부분을 가리킬 때 사용되는 레지스터

f. 스택 메모리의 역할

ㄱ. 함수 내의 로컬변수 임시저장

ㄴ. 함수 호출 시 파라메터 전달

ㄷ. 복귀 주소(return address)를 저장

g. 스택 메모리 주의점

ㄱ. 32/64bit 컴퓨팅 환경에서 스택 크기는 각각 32/64(4/8 byte) 이다.

ㄴ. 스택은 아래로 자란다.

ㄷ. 스택에 값을 입력하면 (PUSH) 스택 포인터는 4byte 만큼 줄어듬

ㄹ. 스택에서 값을 가져오면 (POP) 스택 포인터는 4byte 만큼 늘어남

ㅁ. PUSH, POP, CALL, RET로 ESP를 직접 조작

 

6. EBP(Extended Base Pointer)

a. 함수 인자와 지역 변수를 가리킬 때 사용되는 레지스터

b. 함수가 호출 되었을 때 그 순간의 ESP를 저장하고 있다가, 함수가 리턴하기 직전에 다시 ESP값을 되돌려 줘서 스택이 깨지지 않도록 함(stack frame 기법)

 

7. ESI 와 EDI는 특정 명령어(LODS, STOS, REP, MOVS, etc)와 함께 주로 메모리 복사에 사용

 

8. EIP(Extended Instruction Pointer)

a. CPU가 처리할 명령어의 주소를 나타내는 레지스터이며, 크기는 32bit(4byte) 입니다.

b. 명령어 포인터 EIP 레지스터는 현재 코드 세그먼트에서 다음에 실행될 명령의 offset을 저장

c. EIP는 코드 라인에서 한 경계로 JMP, JCC, CALL, RET, IRET 명령을 실행할 때 명령어 수 만큼 앞 뒤로 이동

d. EIP 레지스터는 소프트웨어에서 직접적으로 액세스 될 수 없다.

e. 이는 흐름제어 명령, 인터럽트, 예외 등을 통하여 암시적으로 제어 된다.

f. EIP 레지스터를 읽는 유일한 방법은 CALL 명령을 실행하여 프로시져 스택의 리턴 명령어 포인터 값을 읽는 것이다.

g. EIP 레지스터는 프로시저 스택에서 리턴 명령어 포인터 값을 수정하고 리턴 명령(RET/IRET)을 수행하여 간접적으로 로드 될 수 있다.

h. CPU는 하나의 명령을 처리하고 난 후 자동으로 그 명령어 길이 만큼 EIP를 증가 시킵니다.

u. General Purpose Register 들과는 다르게 EIP는 그 값을 직접 변경할 수 없도록 되어 있습니다.

안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

출처 : http://blog.naver.com/coofair/40055689793

 

기본적인 프로그램 실행 레지스터

 

8개의 범용레지스터

6개의 세그먼트 레지스터

프로세서의 상태플래그(EFLAGS)와 명령어 포인터(EIP)를 가지고 있는 레지스터 하나

 

 

 

 

범용레지스터 [General Purose Register]

각 레지스터는 하나의 32비트 값으로 혹은 16비트 값으로 처리될 수 있다.

몇 개의 16비트 레지스터는 두 개의 8비트 값으로 분리해서 처리 할 수 있다.

EAX 레지스터는 32비트이고 하위 16비트는 AX 이며 AX의 상위 8비트는 AH 그리고 하위 8비트는 AL이다

 

32비트

16비트

8비트(상위)

8비트(하위)

EAX

AX

AH

AL

EBX

BX

BH

BL

ECX

CX

CH

CL

EDX

DX

DH

DL

 

나머지 범용 16비트에 새로운 이름이 있으나 더 이상 나뉘지는 않는다. 여기서 보여주는 16비트 레지스터는

실제 주소 모드로 수행되는 프로그램 작성 시 보통 사용된다.

 

32비트

16비트

ESI

SI

EDI

DI

EBP

BP

ESP

SP

 

·EAX는 곱셈과 나눗셈 명령에서 자동으로 사용된다.

  종종 확장된 누산기(extended accumulatoe) 레지스터라고 부른다.

·CPU는 루프 카운터로 ECX를 사용한다.

·ESP는 스택영역에 있는 데이터를 가리킨다. 이 레지스터는 일반적인 계산이나 데이터 이동을 위해 절대로 사용될 수 없다.

  이것은 종종 확장 스택 포인터(extended stack pointer)라고 한다.

·ESI와 EDI는 고속의 메모리 전송명령에 사용된다. 이들은 때때로 확장 소스 인텍스(extended source index),확장 도착점 인덱스

  (extended destination index) 레지스터라고 한다.

·EBP는 고급 언어에서 스택 상에 있는 지역 변수와 함수 매개변수를 참조하기 위해 사용된다. 고수준의 프로그래밍이 아니면

  일반적인 계산이나 데이터 이동을 위해 사용해서는 안 된다. 종종 확장 프레임 포인터(extended frame pointer) 레지스터라고

  한다.

  

세그먼트 레지스터(segment register)

실제 모드에서 세그먼트(Segment)라고 하는 미리 할당된 메모리 영역의 시작주소를 가리킨다

프로그램 명령어를 갖고 있으며 다른것들은 변수(데이터)를 가지고 있고 스택 세그먼트 라고 하는 다른 세그먼트는 지역 함수 변수와 함수 매개변수를 가지고 있다.

 

명령어 포인터

EIP는 싱될 다음 명령어의 주소를 갖고 있다.

몇몇 기계어 명령어는 프로그램이 새로운 위치로 분기하게 하기 위하여 이 주소를 조작한다.

 

EFLAGS 레지스터 [또는 플래그(flag)]

CPU의 동작을 제어하기 위해서 또는 CPU의 동작의 결과를 반영하기 위한 개별적인 비트들로 구성된다.

프로세서 플래그를 조사하고 조작하기 위한 기계어 명령어들이 있다.

플래그는 그 값이 1 일때 set되며 0일때 clear 된다.

 

제어 플래그

CPU의 동작을 제어하기 위하여 프로그래머는 EFLAGS 레지스터의 각 비트를 지정한다.

그 예가 방향과 인터럽트 플래그이다

 

상태 플래그

CPU가 산술이나 논리 연산을 수행한 결과를 반영 한다.

플래그에는 오버플로,부호,제로,보조 캐리,패리티, 그리고 캐리 플래그 등이 있다.

 

캐리 플래그 (CF : carry flag)

부호 없는 산술연산의 결과가 너무 커서 저장될 수 없을 때 지정된다.

오버플로 플래그(OF : overflow flag)

부호가 있는 산술연산의 결과가 너무 커서 저장될 수 없을 때 지정된다.

부호 플래그(SF : sign flag)

산술연산이나 논리연산의 결과가 음수를 생성했을 때 지정된다.

제로 플래그(ZF : zero flag)

산술이나 논리연산의 결과가 0일 때 지정된다.

보조 캐리 플래그(auxiliart carry flag)

8비트 피연산자를 사용한 산술연산에서 비트 3에서 비트4로 캐리가 발생했을 때 지정된다.

패리티 플래그(parity flag)

하나의 수에서 지정된 비트의 개수를 합한 것으로 그 합이 홀수 인지 짝수인지를 나타낸다.

 

'Development > Assembly' 카테고리의 다른 글

범용레지스터 종류와 특징  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,
 
 
System Error Codes
 

 

The following topics provide lists of system error codes. These values are defined in the WinError.h header file.

·           System Error Codes (0-499)

·           System Error Codes (500-999)

·           System Error Codes (1000-1299)

·           System Error Codes (1300-1699)

·           System Error Codes (1700-3999)

·           System Error Codes (4000-5999)

·           System Error Codes (6000-8199)

·           System Error Codes (8200-8999)

·           System Error Codes (9000-11999)

·           System Error Codes (12000-15999)

If you are experiencing difficulty with an application you are installing or running, contact customer support for the software that is displaying the error message. To obtain support for a Microsoft product, go to http://support.microsoft.com.

 

 

안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,