모든 내용은 [윤성우 저, "열혈강의 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 소켓 프로그래밍", 오렌지미디어
'Programming > 열혈 TCP, IP 소켓 프로그래밍(저자 윤성우)' 카테고리의 다른 글
Ch 22. Overlapped IO 모델 (0) | 2020.08.15 |
---|---|
Ch 21. Asynchronous Notification IO 모델 (0) | 2020.08.15 |
Ch 20. Windows에서의 쓰레드 동기화 (0) | 2020.08.14 |
Ch 19. 내용 확인문제 (0) | 2020.08.14 |
Ch 19. Windows에서의 쓰레드 사용 (0) | 2020.08.14 |