Thread 1에서는 단일 스레드를 생성하였고 이번에는 멀티 스레드를 생성하여 동작을 확인해 볼 것이다.

 

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
DWORD WINAPI ThreadFunc(LPVOID prc)
{
    HDC hdc;
    BYTE Blue = 0;
    HBRUSH hBrush, hOldBrush;
    RECT rc = *(LPRECT)prc;
    hdc = GetDC(hWndMain);
    for(;;)
    {
        Blue+=5;
        Sleep(20);
        hBrush = CreateSolidBrush(RGB(0,0,Blue));
        hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
        Rectangle(hdc, rc.left,rc.top,rc.right,rc.bottom);
        SelectObject(hdc, hOldBrush);
        DeleteObject(hBrush);
    }
 
    ReleaseDC(hWndMain, hdc);
    return 0;
}
 
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    DWORD ThreadID;
    static RECT arRect[] = {
        {100100200200}, {300100400200},
        {100300200400}, {300300400400},
    };
 
    int i;
 
    switch(iMessage) 
    {
    case WM_CREATE:
        hWndMain = hWnd;
        for (i=0; i<4++i) {
            CloseHandle(CreateThread(NULL,0,ThreadFunc, &arRect[i], 0&ThreadID));
        }
        return TRUE;
    case WM_LBUTTONDOWN:
        hdc = GetDC(hWnd);
        Ellipse(hdc, LOWORD(lParam)-10, HIWORD(lParam)-10, LOWORD(lParam)+10, HIWORD(lParam)+10);
        ReleaseDC(hWnd, hdc);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs

 

상기 소스는 동시에 4개의 스레드가 실행되면서 파란색 사각형을 계속 그리고 있으며 주 스레드는 왼쪽 마우스 클릭 입력을 받아

원을 그리는 동작을 한다. 주 스레드를 포함한 5개의 스레드가 동시에 실행되고 있는 것이다.

 

WM_CREATE에서 4개의 스레드를 생성하는데 같은 동작을 하는 스레드이므로 시작 함수는 모두 ThreadFunc이다.

같은 프로세스 내의 Thread끼리는 주소 공간, 전역 변수, 코드를 공유하므로 같은 시작함수를 사용해도 상관없다.

시작 함수가 같더라도 전달되는 인수가 다르면 다른 동작을 한다. 그러므로 차후에 멀티 스레드를 사용하게 되면 같은 자원에 대해

Thread끼리 자원에 접근하는 순서를 제어할 필요가 있게 된다. (동기화 처리)

 

여기서는 앞에와 다르게 ThreadFunc의 인자를 CreateThread 4번째 인자로 넘겨주었다.

스레드로 전달되는 인자는 LPVOID 형이기 때문에 실제로 어떤 형태의 인수든지 전달할 수 있다.

간단한 정수형도 가능하고 크기가 큰 데이터라면 구조체를 만든 후 그 포인터를 전달하면 된다.

'Programming > Thread' 카테고리의 다른 글

[API] Thread 6 (동기화 - 크리티컬 섹션)  (0) 2017.08.30
[API] Thread 5 (스케줄링)  (0) 2017.08.30
[API] Thread 4 (UI 스레드)  (0) 2017.08.30
[API] Thread 3 (Thread 관리)  (0) 2017.08.29
[API] Thread 1 (단일 Thread)  (0) 2017.08.24

해당 내용들은 김상형 저자님의 윈도우즈 API 정복 #2 에 나오는 내용들입니다.

(API의 바이블이라고 생각하는 도서이며 옆에 껴두고 필요한 부분들을 참고하면서 공부하기 정말 좋은 책입니다.)

 

한 프로그램에서 여러 가지 작업을 동시에 수행해야 할 경우가 있다.

대체로 cpu가 하나뿐이며 폰 노이만형 컴퓨터는 한 번에 하나의 일만 할 수 있으므로 실제로 이것은 불가능하다.

그리하여 나온 것이 Thread 개념이며 여러 Thread들이 번갈아 가면서 조금씩 작업을 함으로써 동시에 실행되는 듯한

효과를 낼 수 있다.

 

Thread는 프로세스 내에 존재하는 일련의 실행 코드이다.

프로세스는 단지 존재하기만 하는 껍데기일 뿐이며 실제 작업은 스레드가 담당한다.

프로세스 생성 시 하나의 주 스레드가 생성되며 대부분의 경우 주 스레드가 모든 작업을 처리하고 주 스레드가 종료되면

프로세스도 같이 종료된다.

 

스레드가 여러개 생긴 경우라면, 주 스레드와 나머지 스레드들은 CPU 시간을 우선 순위에 따라 적절하게 분배하여 동시에

실행된다. 운영체제는 스레드별로 골고루 CPU 시간을 배분하므로 한 스레드가 시간을 지나치게 오래 끌더라도 다른 스레드가

이에 영향을 받지 않고 실행된다.

그러므로 이 방법은 타이머나 PeekMessage를 사용하는 방법보다 반응성이 훨씬 좋다.

 

하나의 운영체제에 여러 개의 프로세스가 동시에 실행되는 환경을 멀티 태스킹이라하며 하나의 프로세스에서 여러 개의 스레드가

동시에 실행되는 환경은 멀티스레드라 한다.

 

<간단한 Thread 생성 코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    DWORD ThreadID;
    HANDLE hThread;
 
    switch(iMessage) 
    {
    case WM_CREATE:
        hWndMain = hWnd;
        hThread = CreateThread(NULL,0,ThreadFunc, NULL0&ThreadID);
        CloseHandle(hThread);
        return TRUE;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
 
cs

 

우선 상기 코드는 주 스레드의 WM_CREATE에서 스레드를 하나 생성한 코드이며 CreateThread 함수를 사용한다.

 

<CreateThread 함수>

1
2
3
4
5
6
7
8
9
10
HANDLE
WINAPI
CreateThread(
    __in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes,
    __in      SIZE_T dwStackSize,
    __in      LPTHREAD_START_ROUTINE lpStartAddress,
    __in_opt  LPVOID lpParameter,
    __in      DWORD dwCreationFlags,
    __out_opt LPDWORD lpThreadId
    );
cs

 

 · Parameter 1 (LPSECURITY_ATTRIBUTES lpThreadAttributes)

 

  - 스레드의 보안 속성을 지정하는데 자식 프로세스로 핸들을 상속하지 않는 한 NULL로 지정하면 된다.

 

 · Parameter 2 (SIZE_T dwStackSize)

 

  - 스레드의 스택 크기를 지정하는데 스레드끼리 상호 안정된 동작을 하기 위해 스레드별로 별도의 스택이 할당된다.

  - 스택의 크기를 0으로 지정하면 주 스레드와 같은 크기를 가진다.

 

 · Parameter 3 (LPTHREAD_START_ROUTINE lpStartAddress)

 

  - 스레드의 시작 함수(Entry Point)를 지정하며 실질적으로 가장 중요한 인자. (주 스레드의 WinMain 함수에 해당)

  - 지정된 함수로부터 스레드의 실행을 시작하며 해당 함수가 종료되면 스레드도 종료된다.

  - 시작 함수는 다음과 같은 원형을 가져야 한다. → DWORD WINAPI ThreadFunc(LPVOID lpParameter);

 

 · Parameter 4 (LPVOID lpParameter)

  

  - Parameter 3에서 지정한 스레드의 시작 함수는 LPVOID형의 인수 하나만 받아들이는데 이 인수는 CreateThread의

    네 번째 인수로 지정한다.

  - 4 번째 인수는 스레드로 전달할 작업 내용을 지정한 것이며, 전달할 내용이 없다면 NULL을 전달하면 된다.

 

 · Parameter 5 (DWORD dwCreationFlags)

 

  - 생성할 스레드의 특성을 지정하는 인자이며 아무 특성이 없는 보통 스레드를 만들고자 한다면 0으로 지정하면 된다.

  - 만약 스레드를 만들기만 하고 실행은 하지 않게 하고 싶다면, CREATE_SUSPENDED 플래그를 지정하면 된다.

 

 · Parameter 6 (LPDWORD lpThreadId)

 

  - CreateThread 함수가 스레드를 만든 후 스레드의 ID를 리턴하기 위한 출력용 인수이므로 DWORD형의 변수를 하나
    선언한 후 주소값을 넘겨준다.

 

CreateThread 함수는 스레드를 만든 후 스레드의 핸들을 리턴하며 에러가 발생했을 경우 NULL을 리턴한다.

리턴된 핸들을 이용하여 스레드를 제어하는데 상기 예제는 생성 후 스레드를 제어하지 않기 때문에 바로 핸들을 닫았다.

스레드 핸들과 스레드 자체는 다르므로 핸들을 닫는다고 해서 스레드가 종료되는 것은 아니다.

'Programming > Thread' 카테고리의 다른 글

[API] Thread 6 (동기화 - 크리티컬 섹션)  (0) 2017.08.30
[API] Thread 5 (스케줄링)  (0) 2017.08.30
[API] Thread 4 (UI 스레드)  (0) 2017.08.30
[API] Thread 3 (Thread 관리)  (0) 2017.08.29
[API] Thread 2 (MultiThread)  (0) 2017.08.29

라이브러리 (Library)

 

함수, 데이터, 타입 등 여러가지 프로그래밍 요소들의 집합이며 보통 lib 확장자를 가진다.

자주 사용되는 함수를 매번 직접 작성해서 사용하는 것은 비생산적인 작업이므로 표준화할 수 있는 함수를 미리 만들어서 모아 놓은 것이 라이브러리이다.

 

이 라이브러리를 프로그램에 링크시키는 방식에 정적 링크와 동적 링크가 있는데 동적 링크 방식을 사용하면 DLL이 된다.

 

 정적 링크 (Static Link)

 

  컴파일 시 라이브러리의 코드를 실행 파일에 복사한다. 때문에 실행 파일의 크기는 커지지만 실행 파일은 단독 실행 파일이 된다.

  컴파일이 끝나면 라이브러리 파일(.lib)이 없어도 프로그램을 실행시킬 수 있다.

 

 동적 링크 (Dynamic Link)

 

  실행 시에 라이브러리가 실행 파일에 연결된다.

  실행 파일에는 호출할 함수의 정보만 포함되고 실제 함수 코드는 복사되지 않으므로 실행 파일의 크기가 작아진다.

  실행 파일에는 실제 라이브러리 코드가 없기 때문에 프로그램 실행 시 DLL이 반드시 있어야 한다.

 

 동적 링크 장점

 

  여러 프로세스가 메모리에 있는 하나의 DLL 복사본을 공유하여 하나의 DLL을 동시에 사용할 수 있다.

  반면, 정적 연결 라이브러리를 사용하여 빌드된 응용 프로그램의 경우 Windows는 각 응용 프로그램에 대해 하나의 라이브러리 코드

  복사본을 메모리에 로드해야 한다.

 

  디스크 공간을 절약할 수 있다. 여러 응용 프로그램이 디스크에 있는 하나의 DLL 복사본을 공유할 수 있다.

  반면, 정적 연결 라이브러리를 사용하여 빌드된 응용 프로그램의 경우에는 각 응용 프로그램마다 별도의 복사본으로서 실행 가능한

  이미지에 링크되는 라이브러리 코드가 있다.

 

  DLL을 보다 쉽게 업데이트 할 수 있다. DLL의 함수가 변경되어도 이 함수의 인수 및 반환 값이 변경되지 않았으면 그 함수를 사용하는

  응용 프로그램을 다시 컴파일하거나 링크할 필요가 없다.

 

  반면, 정적으로 링크되는 개체 코드의 경우에는 함수가 변경되면 응용 프로그램을 다시 링크시켜야 한다.

 

DLL 관리

 

DLL은 가상 메모리에 한 번 로드되면 다시 로드 되지 않는다.

DLL이 메모리에서 삭제되어야 할 시기는 DLL을 사용하는 모든 응용 프로그램이 종료되었을 때이다.

윈도우즈는 DLL별로 사용 카운트(참조 카운트)라는 것을 이용하여 해당 DLL을 사용하는 응용 프로그램이 실행될 때마다 카운트를

1 증가시키고 응용 프로그램이 종료될 때마다 카운트를 1 감소시킨다.

그러다 카운트가 0이 되었을 때 메모리가 삭제된다.

 

DLL Export, Import

 

 Export

 

  함수를 제공하는 DLL에서는 자신이 제공하고자 하는 함수에 대한 정보를 밖으로 공개해야 하며 이 동작을 Export라 한다.

  __declspec은 함수에 대한 정보를 제공하는 선언문이며 Export할 함수 원형 앞에 집어넣으면 된다.

 

1
2
3
4
extern "C" __declspec(dllexportint Add(int a, int b)
{
    return a+b;
}
cs

 

 Import

 

  반대로 DLL을 사용하는 응용 프로그램에서는 어떤 DLL에 있는 어떤 함수를 사용하겠다고 선언해야 하는데 이 동작을 Import라고 한다.

  응용 프로그램에서 사용할 DLL 함수를 아래와 같이 Import하여 사용할 수 있다.

 

1
extern "C" __declspec(dllimportint Add(intint);
cs

 

Import Library

 

DLL을 사용할 프로그램은 자신이 Import할 함수가 어느 DLL에 있는지 알아내기 위해 Import Library를 사용한다.

Import Library는 DLL에서 Export 되는 함수에 대한 정보는 물론 이 함수의 코드가 어떤 DLL에 정의되어 있는지에 대한 정보를 가지고 있다.

단, 함수에 대한 정보만 가지고 있을 뿐 함수의 코드는 가지고 있지 않다.

그래서 응용 프로그램은 링크 시에 Import Library(.lib)를 링크해야 하며 Import Library가 지정하는 DLl 파일을 실행시에 읽어와야 한다.

 

Import Library는 함수에 대한 위치 정보만 가지고 있으므로 컴파일 할때만 필요하며 프로그램 실행과는 아무 상관이 없다.

그래서 DLL 배포시에는 .dll File만 배포하면 된다.

 

MyProject 라는 DLL 생성 프로젝트를 컴파일하면 MyProject.dll (DLL)과 MyProject.lib (Import Library) 두 개의 파일이 생긴다.

 

참고 자료

http://stdesignstar.tistory.com/tag/dll

 

 

'Programming > Knowledge' 카테고리의 다른 글

컴퓨터에 수가 저장되는 방법.  (0) 2017.04.20

<Client>

 

5. Server 연결. (Server에 전화 걸기.)

 · SOCKADDR_IN 구조체 선언. (주소 패밀리와 IP, 포트 번호를 쉽게 참조할 수 있도록 만들어진 구조체)

 · connect 함수 호출. (Server에 접속 요청)

 

  - SOCKADDR_IN 구조체

   sin_family : 프로토콜 체계를 정의한다. (인터넷 기반 [IPv4]의 경우는 AF_INET)

   sin_addr : Server의 IP 주소 정보를 넣어준다.

   sin_port : Server의 Port 정보를 넣어준다.

 

  - connect 함수

   Parameter 1 : 미리 생성한 socket을 넣어준다.

   Parameter 2, 3 : 미리 생성한 SOCKADDR_IN 구조체 정보를 넣어준다.

 

   Return : 정상적으로 연결되지 않을 경우 SOCKET_ERROR 값을 반환한다. (winsock2.h에 상수값으로 정의되어 있음.)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
    SOCKADDR_IN ServerInfo;
 
    ServerInfo.sin_family = AF_INET;
    ServerInfo.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    ServerInfo.sin_port = htons(2011);
    
    int Result = connect(m_Socket, (SOCKADDR*)&ServerInfo, sizeof(ServerInfo));
    if(Result == SOCKET_ERROR)
    {
        closesocket(m_Socket);
        WSACleanup();
        return false;
    }
cs

 

6-1. Data 송신 (Server에게 말하기)

 · send 함수 호출. (Block 함수이므로 해당 일이 끝날때까지 리턴되지 않고 대기한다.)

 

  - send 함수

   Parameter 1 : 미리 생성한 socket을 넣어준다.

   Parameter 2 : 보낼 Data를 넣어준다. (char형의 포인트이므로 구조체던지 int형이던지 적절한 캐스팅 연산자를 사용해 어떤 데이터든지 보낼 수 있다.)

   Parameter 3 : Parameter 2의 크기.

   Parameter 4 : 함수 호출 시에 여러가지 옵션을 설정할 수 있다. (특별한 옵션을 주지 않으면 0을 넣어준다.)

 

   Return : 정상 송신 시 데이터를 보낸 양만큼의 Byte 크기를 반환 / 에러 발생 시 SOCKET_ERROR를 반환.

 

6-2. Data 수신 (Server의 말 듣기)

 · recv 함수 호출. (Block 함수이므로 해당 일이 끝날때까지 리턴되지 않고 대기한다.)

 

  - recv 함수

   Parameter 1 : 미리 생성한 socket을 넣어준다.

   Parameter 2 : Data를 담을 Bufer를 넣어준다. 
                     (char형의 포인트이므로 구조체던지 int형이던지 적절한 캐스팅 연산자를 사용해 어떤 데이터든지 받을 수 있다.)

   Parameter 3 : Server로부터 받을 Data의 크기를 모르기 때문에 넉넉히 잡아주는 것이 좋다.

   Parameter 4 : 함수 호출 시에 여러가지 옵션을 설정할 수 있다. (특별한 옵션을 주지 않으면 0을 넣어준다.)

 

   Return : 정상 수신 시 받은 데이터 양만큼의 Byte 크기를 반환 / 에러 발생 시 SOCKET_ERROR를 반환.

 

* Block 함수 주의점 (send, recv, accept 함수)

  Server 측에서 어떤 Client에게 데이터를 전행할 때, Client 측에서 recv함수로 Server가 보낸 Data를 받지 않는다면 대기 상태로 들어가게 된다.

  send, recv 함수는 해당 동작이 끝날때까지 리턴되지 않고 대기하는 Block 함수이기 때문이다.

  Block 함수를 사용할 때는 Server & Client 프로그램 간의 실행구조를 잘 생각해야 한다.

 

 

 

'Programming > Socket' 카테고리의 다른 글

[API] 소켓 통신 2 <Server/Client 공통>  (0) 2017.05.22
[API] 소켓 통신 1 <Server/Client 흐름도>  (0) 2017.05.22

- API SOCKET 사용하기.

 

C++에서 소켓 통신을 하기 위해서 API에서 제공하는 SOCKET을 이용하면 된다.

 

<Server / Client 공통>

 

 1. Header File 추가 & Lib 연결.

  · winsock2.h Header File Include.

  · ws2_32.lib Library 링크.

   (프로젝트마다 링크를 시켜줘야 하는 불편함이 있기 때문에 하기와 같이 프로그램으로 선언해두면 자동으로 링크가 된다.)

 

1
2
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
cs

 

 2. Socket 변수 선언

  · SOCKET형 변수.

  · WSDATA형 변수. 

 

1
2
SOCKET m_Socket;
WSADATA m_wsaData;
cs

 

3. ws2_32.lib 초기화.

  · WSAStartup 함수 호출. (Window Socket을 사용하겠다고 System에 알려주는 함수)

  · WSAStartup 함수는 ws2_32.lib를 초기화 해주어 Window Socket을 사용할 수 있도록 해준다.

  · WSAStartup 함수를 호출해야 Winsock 관련 함수를 사용할 수 있다.

  · Winsock 종료 시에는 반드시 WSACleanup() 을 호출해야만 한다.

 

  - WSAStartup 함수.

  Parameter 1 : 사용할 소켓의 버전이 2.2라는 것을 알려준다.

  Parameter 2 : WSDATA 구조체 변수의 주소값을 넘겨주면 해당 변수에 초기화된 라이브러리 정보가 채워진다.

 

  Return : 정상적으로 초기화가 되면 0 값을 반환.

 

1
2
3
4
5
6
    if(WSAStartup(MAKEWORD(2,2), &m_wsaData) == INVALID_SOCKET)
    {
        printf("WSAStartup() failed : %d", WSAGetLastError());
        WSACleanup();
        return false;
    }
cs

 

4. Socket 생성. (전화기 장만)

  · Socket을 만들어주는 함수.

 

  - socket 함수.

  Parameter 1 : 주소 패밀리(Address Family)를 적어준다. (Internet Protocol 4 (IPv4)를 사용한다면 AF_INET)

  Parameter 2 : 소켓 타입을 적어준다. (SOCK_STREAM : TCP 방식 / SOCK_DGRAM : UDP 방식)

  Parameter 3 : Protocol (0 값을 넣어주면 그에 맞는 Protocol을 사용하도록 한다.)

 

  Return : 성공적으로 Socket이 만들어지면 SOCKET형 데이터를 반환. / 실패 시 INVALID_SOCKET 반환.

 

1
2
3
4
5
6
    m_Socket = socket(AF_INET, SOCK_STREAM, 0);
    if(m_Socket == INVALID_SOCKET)
    {
        printf("socket() failed : %d", WSAGetLastError());
        return false;
    }
cs

 

'Programming > Socket' 카테고리의 다른 글

[API] 소켓 통신 4 <Client>  (0) 2017.05.22
[API] 소켓 통신 1 <Server/Client 흐름도>  (0) 2017.05.22

- SOCKET 이란?

 

두 프로그램이 네트워크를 통해 서로 통신을 수행 할 수 있도록 양쪽에 생성되는 링크의 단자.

두 소켓이 연결되면 서로 다른 프로세스끼리 데이터를 전달 할 수 있다.

 

- Server / Client 흐름도.

 

Server/Client는 전화기에 비율할 수 있다.

 

Server : 전화를 받는 사람.

Client : 전화를 거는 사람.

 

Server는 먼저 실행중인 상태여야 하고 Client의 접속을 허락하고 관리할 수 있어야 한다.

즉, Server는 Client에게 전화가 올 때까지 기다리고 있다가 Client가 전화를 걸면 전화를 받는다.

 

<Server>

 

 1. 전화기가 장만한다. (socket 함수)

 2. 전화 번호를 할당 받아야 한다. (bind 함수)

 3. 전화가 걸려올 수 있도록 전화기를 잭에 연결한다. (listen 함수)

 4. Client로부터 전화가 걸려오면 받는다. (accept 함수)

 5. Client와 대화를 주고 받는다. (send, recv 함수)

 6. 대화가 끝나면 전화를 끊는다. (closesocket 함수)

 

<Client>

 

 1. 전화기가 장만한다. (socket 함수)

 2. Server에 전화를 건다. (connect 함수)

 3. Server와 대화를 주고 받는다. (send, recv 함수)

 4. 대화가 끝나면 전화를 끊는다. (closesocket 함수)

 

참고 내용.

 http://cafe.naver.com/nevernding

'Programming > Socket' 카테고리의 다른 글

[API] 소켓 통신 4 <Client>  (0) 2017.05.22
[API] 소켓 통신 2 <Server/Client 공통>  (0) 2017.05.22

컴퓨터가 메모리에 데이터를 저장하는 방법.

 

메모리에 Data가 적재되는 방법으로는 Little Endian 방식과 Big Endian 방식이 있다.

 

Big Endian 방식.

 · 사람과 동일하게 앞에서부터 순차적으로 데이터를 저장하는 방식.

 · 모토롤라 관련 CPU, IBM or 썬마이크로시스템즈의 컴퓨터들이 사용하는 방식.

 · Java의 자바 가상 머신은 운영체제나 하드웨어 상관없이 항상 Big Endian을 사용.

 

 

 ex) 0x12345678 값을 저장한다면 하기와 같은 방식으로 메모리에 저장된다.

 

주소

0x0001

0x0002

0x0003

 0x0004

Data

0x12

0x34

0x56

0x78

 

 

Little Endian 방식.

 

 · Big Endian 방식과 반대로 메모리에 역순으로 데이터를 저장하는 방식

 · Intel 사의 칫셋과 호환이 되는 컴퓨터들이 사용하는 방식.

 

 ex) 0x12345678 값을 저장한다면 하기와 같은 방식으로 메모리에 저장된다.

 

주소

0x0001

0x0002

0x0003

 0x0004

Data

0x78

0x56

0x34

0x12

 

현재 사용중인 컴퓨터에서 어떤 방식으로 저장되는지 확인해보기.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "stdafx.h"
 
using namespace std;
 
int _tmain(int argc, _TCHAR* argv[])
{
    int i = 0x12345678;
 
    int* p = &i;
    
    char* p1 = (char *)&i;
    char* p2 = (p1 + 1);
    char* p3 = (p2 + 1);
    char* p4 = (p3 + 1);
 
    printf("%p : %x\n", p, *p);
    printf("%p : %x\n", p1, *p1);
    printf("%p : %x\n", p2, *p2);
    printf("%p : %x\n", p3, *p3);
    printf("%p : %x\n", p4, *p4);
 
    return 0;
}
cs

 

<결과>

 

주소

0x002DF928

0X002DF929

0X002DF92A

 0x002DF922B

Data

0x78

0x56

0x34

0x12

 

현재 사용중인 lenovo T530 노트북은 Little Endian 방식임을 알 수 있다.

(결과 주소는 PC마다 다르게 나올 수 있음.)

 

 

컴퓨터가 음수를 처리하는 방법.

 

컴퓨터는 첫 번째 비트를 부호 표현을 위해 따로 배정한다.

이를 부호 비트(signed bit)라 부르며 부호 비트가 0이면 양수, 1이면 음수를 나타내게 된다.

 

논리 회로가 음수를 표현하는 방법은 대표적으로 3가지가 있다.

 

 1. 부호 절대값 방법.

  부호 비트를 제외한 수를 양수 값으로 읽고, 마이너스를 붙이는 방법.

  +3 = 00000011₂

  -3 = 10000011₂

  사람이 사용하기에는 편하지만, 이진수 계산이 안되기 때문에 컴퓨터에선 사용할 수 없다.

 

 2. 1의 보수 방법.

  양수 값의 비트를 반전시켜 음수를 표현하는 방법.

  +3 = 00000011₂

  -3 = 11111100₂

  값이 0인 경우에는 00000000₂ 과 11111111₂ 두 값이 모두 0을 나타낼 수 있기 때문에 컴퓨터에선 사용하지 않는다.

 

 3. 2의 보수 방법.

  1의 보수 방법에서 1을 더하는 방법.

  +3 = 00000011₂

  -3 = 11111101₂

  1의 보수 방법과 다르게 11111111₂이 -1 값을 의미하므로 0과 구분된다.

 

위와 같은 이유로 컴퓨터는 2의 보수 방법으로 음수를 표현한다.

'Programming > Knowledge' 카테고리의 다른 글

DLL (Dynamic Link Library) 1  (0) 2017.05.26

하기 내용은 이재규 교수님의 "C++로 배우는 자료구조와 알고리즘"을 보고 공부한 내용입니다.

문제 시 삭제하도록 하겠습니다.

 

알고리즘(Algorithm)의 정의

 - 주어진 문제를 해결하기 위한 방법

 - 어떻게 할 것인가 해결적 측면.

 

자료구조 (Data Structure)

 - 알고리즘의 객체.

 - 배열, 스택, 큐, 트리 ...

 

알고리즘 선택

 - 하나의 문제에 대해 여러 알고리즘 존재.
   · 예를 들어, 서울에서 부산을 가능 방법은 여러 가지가 있다. (버스, 기차, 자가용 등..)

 

 - 절대적인 최상의 알고리즘은 없다.
   · 주어진 환경에 따라 알고리즘의 효율성은 달라진다.
   · 예를 들어, 출퇴근 시간에는 자동차보다 지하철이 더 빠르게 갈 수 있다. 그러나 차가 없는 저녁 시간에는 자동차가 더 빠를 수 있다.

 

 - 속도와 자원의 상관관계
   · 속도가 빠른 알고리즘은 자원을 많이 차지한다.
   · 메모리가 별로 없는 임베디드 시스템에서는 자원을 적게 차지하는 알고리즘을 선택하는 것이 좋고,

     PC와 같은 충분한 메모리와 고성능 CPU를 가지고 있다면 자원을 많이 차지하더라도 속도에 효율성이 있는 알고리즘을 선택하는 것이 좋다.

 

 - 단순한 알고리즘이 좋다.

   · 지나치게 속도만을 생각하는 것은 좋지 않다.

   · 알고리즘 부분의 사용빈도에 따라 선택하는 것이 좋다.

 

 

알고리즘의 유형

 - 1 (상수)

  · 입력자료수와 관계없이 일정한 실행시간 (데이터가 100개이든 1000개이든 실행 시간은 동일)

  · 해쉬 검색 알고리즘 등

 

 - log N

  · Divide & Conquer 방법 사용 시 (문제를 분할하고 그 분할된 문제를 해결하는 방법)

  · 이진검색, 이진트리검색 등

 

 - N

  · Scan 방법 사용 시 (자료가 100개 들어오면 100초 걸린다면 1000개 일때는 1000초 걸린다.)

  · 선형검색 등 (데이터베이스에서 검색하는 것이 이런 유형)

 

 - N log N

  · Divide & Conquer & Merge 방법 사용 시 (문제를 분할하고 정복하고 다시 합치는데 사용하는 방법)

  ·  병합정렬 등

 

 - N²

  · 이중루프

  · 삽입정렬, 선택정렬 등

 

 - N³

  · 삼중루프

 

하기 그래프는 각 유형 별 결과 그래프이다.

자료 수가 적을 때는 차이가 나지 않지만 자료 수가 늘어남에 따라 실행 결과의 격차는 커진다.

그러므로 적절한 알고리즘을 찾는 것은 매우 중요하다.

 

                        <이재규 교수님 강의 자료 첨부>

+ Recent posts