본문 바로가기
Programming/열혈 TCP, IP 소켓 프로그래밍(저자 윤성우)

Ch 20. 내용 확인문제

by minjunkim.dev 2020. 8. 15.

    모든 내용은 [윤성우 저, "열혈강의 TCP/IP 소켓 프로그래밍", 오렌지미디어] 를 기반으로 제 나름대로 이해하여 정리한 것입니다. 다소 부정확한 내용이 있을수도 있으니 이를 유념하고 봐주세요!


01. 윈도우 운영체제의 유저모드, 커널모드와 관련해서 옳은 것을 모두 고르면?

 

# 옳지 않은 설명

 

a. 유저모드는 응용 프로그램이 실행되는 기본모드로, 접근할 수 있는 메모리의 영역에는 제한이 없지만 물리적인 영역으로의 접근은 허용되지 않는다.

=> 접근할 수 있는 메모리의 영역도 제한된다.

 

b. 응용 프로그램이 실행되는 과정에서는 절대 커널모드로 진입하지 않는다. 응용 프로그램이 실행중인 과정에서는 유저모드로만 동작한다.

=> 응용 프로그램의 실행과정에서 항상 유저모드에만 머무는 것이 아니라, 유저모드와 커널모드를 오가며 실행하게 된다.

 

c. 윈도우는 메모리의 효율적인 사용을 위해서 유저모드와 커널모드를 각각 별도로 정의하고 있다.

=> 안정성을 높이기 위해 두 가지 모드를 정의하고 있다.

 

d. 응용 프로그램이 실행되는 과정에서도 커널모드로의 변환이 발생할 수 있다. 단, 일단 커널모드로 변환이 되면, 프로세스는 이 상태로 실행을 계속 이어하게 된다.

=>

유저모드(응용 프로그램에서 리소스 생성을 요청) => 커널모드(리소스의 생성) => 유저모드(응용 프로그램의 나머지 부분을 이어서 실행)

위와 같은 모드 변환의 과정을 기본적으로 거친다.

 


02. 유저모드 동기화, 커널모드 동기화와 관련된 다음 문장들 중에서 말하는 바가 옳으면 O, 틀리면 X를 표시하자.

 

- 유저모드 동기화는 커널모드로의 전환을 수반하지 않는다. 즉, 운영체제 레벨에서 제공되는 기능의 동기화가 아니다. O

 

- 커널모드 동기화는 운영체제를 통해서 제공되는 기능이므로, 유저모드 동기화에 비해서 많은 기능을 제공한다. O

 

- 커널모드 동기화 과정에서는 유저모드에서 커널모드로, 다시 커널모드에서 유저모드로의 전환과정이 수반된다는 단점이 있다. O

 

- 특별한 경우가 아니면 커널모드 동기화를 사용하는 것이 원칙이다. 유저모드 동기화는 커널모드 동기화가 제공되기 이전의 동기화 기법이다. X

 


03. 본문의 예제 SyncSema_win.c의 Read 함수는 임계영역을 빠져나가는데 오랜 시간이 걸리도록 정의가 되어있다. 이에 대한 해결책을 제시하고 실제 예제에 적용해 보자.

 

unsigned WINAPI Read(void* arg)
{
    int i;
    
    for(i=0;i<5;++i)
    {
        fputs("Input num: ",stdout);
        WaitForSingleObject(semTwo,INFINITE); // semTwo를 non-signaled로 변경
        scanf("%d",&num);
        ReleaseSemaphore(semOne,1,NULL); // semOne을 signaled로 변경
    }
    
    return 0;
}

scanf 함수 호출과 같이 일정시간 이상 대기상태에 놓일 수 있는 함수의 호출은 가급적이면 임계영역에 포함시키지 말아야 한다. 따라서,

unsigned WINAPI Read(void* arg)
{
    int i, readData;
    
    for(i=0;i<5;++i)
    {
        fputs("Input num: ",stdout);
        scanf("%d",&readData);
        WaitForSingleObject(semTwo,INFINITE); // semTwo를 non-signaled로 변경
        num=readData;
        ReleaseSemaphore(semOne,1,NULL); // semOne을 signaled로 변경
    }
    
    return 0;
}

04. 본문의 예제 SyncEvent_win.c를 세마포어 기반의 동기화 기법을 적용해서 동일한 실행결과를 보이도록 재 구현해 보자.

#include <stdio.h>
#include <windows.h>
#include <process.h>

#define STR_LEN 100

/* thread의 main 함수 */
unsigned WINAPI NumberOfA(void* arg);
unsigned WINAPI NumberOfOthers(void* arg);

static char str[STR_LEN];
/* 세마포어 커널 오브젝트의 핸들 */
static HANDLE hSem;

int main(int argc, char* argv[])
{
    HANDLE hThread1, hThread2; // 쓰레드의 핸들
    
    /*
    세마포어 초기값은 0, 최대값은 2
    non-signaled 상태의 세마포어 커널 오브젝트 생성 
    */
    hSem=CreateSemaphore(NULL,0,2,NULL);     
    
    /* 쓰레드 생성 및 실행 */
    hThread1=(HANDLE)_beginthreadex(NULL,0,NumberOfA,NULL,0,NULL);
    hThread2=(HANDLE)_beginthreadex(NULL,0,NumberOfOthers,NULL,0,NULL);
    
    /*
    문자열을 입력받은 후에,
    세마포어를 signaled 상태로 변경
    */
    fputs("Input string: ",stdout);
    fgets(str,STR_LEN,stdin);
    ReleaseSemaphore(hSem,2,NULL);
    
    /* 각 쓰레드가 종료할 때까지 블로킹 */
    WaitForSingleObject(hThread1,INFINITE);
    WaitForSingleObject(hThread2,INFINITE);
    
    ResetEvent(hSem); // 세마포어를 non-signaled 상태로 변경
    CloseHandle(hSem); // 세마포어 소멸
    
    return 0;
}

unsigned WINAPI NumberOfA(void* arg)
{
    int i, cnt=0;
    
    /*
    문자열을 입력 받은 후에야 함수를 반환
    auto-reset 모드이므로 세마포어 값 1 감소
    */
    WaitForSingleObject(hSem, INFINITE);
    
    for(i=0;str[i]!='\0';++i)
    {
        if(str[i]=='A')
            ++cnt;
    }
    printf("Num of A: %d \n",cnt);
    
    return 0;
}

unsigned WINAPI NumberOfOthers(void* arg)
{
    int i, cnt=0;
    
    /*
    문자열을 입력 받은 후에야 함수를 반환
    auto-reset 모드이므로 세마포어 값 1 감소
    */
    WaitForSingleObject(hSem, INFINITE);
    
    for(i=0;str[i]!='\0';++i)
    {
        if(str[i]!='A')
            ++cnt;
    }
    printf("Num of others: %d \n",cnt-1); // 문자열에 개행문자도 포함되어 있으므로 -1
    
    return 0;
}

 


[출처] : 윤성우 저, "열혈강의 TCP/IP 소켓 프로그래밍", 오렌지미디어