일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- MFC
- 셰이더프로그래밍
- 컴퓨터 아키텍쳐
- MFC 윈도우 프로그래밍
- 윈도우 구조
- 윈도우
- 셰이더
- window programming
- win32
- Mesh Processing
- Geometry Modeling
- 윈도우 프로그래밍
- 베지에 곡선
- c4d
- 그래픽스기초
- 컴퓨터 구조
- shader
- 운영체제
- Win32 API
- 그래픽스
- 오픈지엘
- bezier curve
- 윈도우프로그래밍
- shader programming
- OpenGL
- denoising
- Graphics
- modeling
- 렌더링
- 핵심 API로 배우는 윈도우프로그래밍
- Today
- Total
오다기리 박의 알고리즘 노트
8장. 프로세스간 통신(IPC) 2 본문
8장. 프로세스간 통신(IPC) 2
1. 핸들 테이블과 오브젝트 핸들의 상속
도입배경
MS에서는 Windows운영체제를 공개하지 않고 있기 때문에 핸들테이블이 어떻게 관리되는지 자세하게 알 수 없다.
Windows운영체제의 종류 및 버전마다 핸들 테이블이 관리되는 방법에 다소 차이가 있다.
프로세스의 커널 오브젝트 핸들 테이블
핸들 테이블 : 핸들 정보를 저장하고 있는 테이블로서 프로세스별로 독립적이다.
프로세스가 CreateMailslot() 호출을 통해 메일슬롯 리소스를 생성 요구 -> 커널 오브젝트 생성 -> 커널 오브젝트의 핸들 정보를 얻게됨 -> 프로세스 자신에게 속해 있는 핸들 테이블에 해당 정보가 등록됨 -> 256이 0x2400번지에 존재하는 커널 오브젝트에 접근이 가능하게 됨 -> CreateMailslot() 함수를 빠져 나오면서 핸들값 반환핸들의 상속
CreateProcess() 함수를 호출하면 새로운 자식 프로세스가 생성되고 자식 프로세스를 위한 핸들 테이블도 더불어 생성된다.
CreateProcess() 함수 호출 시 bInheritHandles 인자에 따라(TRUE : 상속 여부가 Y인 핸들에 한해서만 상속, FALSE : 상속X) 부모 프로세스 핸들 테이블에 등록되어 있는 핸들 정보가 자식 프로세스에게 상속될 수 있다.
상속여부 정보도 그대로 상속됨 -> 또 다른 자식 프로세스 생성시 핸들 정보 계속 상속핸들이 상속될 때 커널 오브젝트의 Usage Count
-> 자식 프로세스 생성 이전의 부모 프로세스 구성형태.
-> 부모 프로세스가 자식 프로세스를 생성하면서 핸들 테이블을 상속한 상태.핸들의 상속 여부(핸들 테이블에서의 Y/N)는 리소스가 생성되는 순간에 프로그래머에 의해 결정된다.
//메일슬롯의 핸들을 이후에 생성되는 자식 프로세스에게 상속하기 위한 코드 … SECURITY_ARRTIBUTES sa; sa.nLength=sizeof(sa); sa.lpSecurityDescriptor=NULL; sa.bInheritHandle=TRUE; … CreateMailslot(... , &sa , ...); //4번째 전달인자 ... |
//자식 프로세스의 핸들을 이후에 생성되는 자식 프로세스에게 상속하기 위한 코드 … SECURITY_ATTRIBUTESsa; sa.nLength=sizeof(sa); sa.lpSecurityDescriptior=NULL; sa.bInheritHandle=TRUE; … CreateProcess(... , &sa , ...); //3번째 전달인자 ... |
CreateProcess() 호출 시 핸들 상속과 관련해서 결정할 두 가지 사항
자식 프로세스에게 핸들 테이블을 상속할 것인가
자식 프로세스 생성 시 얻게 되는 핸들(자식 프로세스를 가리키는 핸들)의 상속 여부
메일슬롯 예제
Pseudo 핸들과 핸들의 Duplicate
GetCurrentProcess() 함수는 현재 실행 중인 프로세스를 참조하기 위한 용도로 정의해 놓은 약속된 상수를 반환한다. 즉 pseudo핸들을 반환한다.
진짜 핸들 얻기
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
LPHANDLE lpTargetHandle,
DWORD dwDesireAccess,
BOOL bInheritHandle,
DWORD dwOptions
);
함수 실패시 반환값은 0hSourceProcessHandle : 복제할 핸들을 소유하는 프로세스
hSourceHandle : 복제할 핸들
hTargetProcessHandle : 복제된 핸들을 소유할 프로세스
lpTargetHandle : 복제된 핸들값을 저장할 변수의 주소
dwDesireAccess : 복제된 핸들의 접근권한 지정. DUPLICATE_SAME_ACCESS를 dwOptions의 인자로 전달시 이 인자 무시
bInheritHandle : 복제된 핸들의 상속 여부 .TRUE 전달 시 새로운 자식 프로세스로 상속될 수 있음.
dwOptions : DUPLICATE_SAME_ACCESS 전달 시 원본 핸들과 동일한 접근권한을 갖게됨. DUPLICATE_CLOSE_SOURCE 전달 시 원본 핸들 종료 시킴. OR연산자로 이들을 동시 전달 가능.
핸들 테이블에 등록되어야 진정한 복사이다.
핸들 테이블은 프로세스별로 독립적이기 때문에 핸들이 복사된다고 해서 핸들값까지 똑같은 것은 아니다.
DuplicateHandle() 함수에 의해 핸들이 복사되면 UC는 증가한다. 따라서 복사된 핸들에 대해서도 CloseHandle() 호출을 통해 핸들을 반환해야 한다.
2. 파이프 방식의 IPC
메일슬롯에 대한 회고와 파이프의 이해
메일슬롯
서로 관련이 없는 프로세스들(네트워크로 통신하거나 부모 자식간의 연관 관계가 없는 프로세스들)사이에서 통신할 때 유용한 IPC 기법.
메일슬롯에 할당된 주소를 기반으로 통신하기 때문에 관계없는 프로세스들 사이에서 통신 가능
브로드캐스트 방식의 단방향 통신방식
Anonymous 파이프
단방향 통신방식을 취하며, 파이프를 통해서 생성된 핸들을 기반으로 통신하기 때문에 관계가 있는(부모 자식 관계, 형제 관계) 프로세스들 사이에서 통신하는 경우에 유용
Named 파이프
메일슬롯과 유사. 차이점은 브로드캐스트 방식을 지원하지 않는 대신 양방향 통신을 지원
Anonymous 파이프
‘비가 올 때 옥상에 고인 물을 배수하기 위해 땅으로 연결되어 있는 배수 파이프’
BOOL CreatePipe(
PHANDLE hReadPipe,
PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttributes,
DWORD nSize
);
함수 실패시 반환값은 0hReadPipe : 파이프 끝(데이터를 읽기 위한)에 해당하는 핸들을 얻게됨
hWritePipe : 다른 한쪽 끝(데이터를 쓰기 위한)에 해당하는 핸들을 얻게됨
lpPipeAttributes : 보안 관련 정보 전달. 핸들의 상속 특성을 지정할 때 사용
nSize : 파이프의 버퍼 사이즈를 지정. 0 전달시 디폴트 사이즈
Named 파이프
HANDLE CreateNamedPipe(
LPCTSTR lpName,
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
함수 실패시, 반환값은 INVALID_HANDLE_VALUElpName : 파이프 이름 지정. ex) \\.\pipe\pipename
dwOpenMode : 다음 셋 중 하나를 지정. 읽기/쓰기 모드를 지정
PIPE_ACCESS_DUPLEX : 읽기, 쓰기 모두 가능
PIPE_ACCESS_INBOUND : 서버 입장에서 읽기만 가능
PIPE_ACCESS_OUTBOUND : 서버 입장에서 쓰기만 가능
dwPipeMode : 데이터 전송 타입, 데이터 수신 타입, 블로킹 모드 설정
데이터 전송방식
PIPE_TYPE_BYTE(바이너리 형태)
PIPE_TYPE_MESSAGE(텍스트 형태)
데이터 수신방식
PIPE_READMODE_BYTE(바이너리 방식)
PIPE_READMODE_MESSAGE(텍스트 방식)
함수 리턴방식
PIPE_WAIT(블로킹)
PIPE_NOWAIT(논블로킹 쓰지않음)
ex) 문자열 주고 받을 때는 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT
ex) 바이너리 데이터를 주고 받을 때는 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT
nMaxInstances : 생성할 수 있는 파이프의 최대 개수 지정. 지정한 수만큼 파이프 클라이언트의 연결 요청을 수용 가능. 범위는 1~PIPE_UNLIMITED_INSTANCES(생성가능한 최대 개수)
nOutBufferSize : 이름있는 파이프의 출력 버퍼 사이즈 지정. 0입력시 디폴트값
nInBufferSize : 이름있는 파이프의 입력 버퍼 사이즈 지정. 0입력시 디폴트값
nDefaultTimeOut : WaitNamedPipe() 함수에 적용할 기본 만료 시간
lpSecurityAttributes : 보안 속성 지정
BOOL ConnectNamedPipe(
HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped
);
함수 실패시, 반환값은 0hNamePipe : CreateNamedPipe() 함수 호출을 통해서 생성한 파이프의 핸들
lpOverlapped : 중첩 I/O를 위한 전달인자. 보통 NULL
BOOL WaitNamedPipe(
LPCTSTR lpNamedPipeName,
DWORD nTimeOut
);
타임아웃이 흐르기 전에 파이프의 인스턴스가 사용불가라면 반환값은 0이다.lpNamedPipeName : 상태 확인의 대상이 되는 파이프 이름
nTimeOut : 타임아웃 시간. 이 시간이 지나면 FALSE 반환. NMPWAIT_WAIT_FOREVER로 설정시 연결가능한 상태가 될 때까지 기다리게 되며, NMPWAIT_USE_DEFAULT_WAIT로 설정시 서버에서 CreateNamedPipe() 함수를 호출하면서 전달한 7번째 인자를 통해 결정된 디폴트 시간만큼만 기다림.
BOOL SetNamedPipeHandleState(
HANDLE hNamedPipe,
LPDWORD lpMode,
LPDWORD lpMaxCollectionCount,
LPDWORD lpCollectDataTimeOut
);
함수 실패시 반환값은 0hNamedPipe : 파이프와의 연결 속성을 변경시키기 위한 핸들
lpMode : 읽기 모드와 함수 리턴방식에 대한 값을 OR 연산으로 전달.
데이터 전송방식
PIPE_TYPE_BYTE(바이너리 형태)
PIPE_TYPE_MESSAGE(텍스트 형태)
데이터 수신방식
PIPE_READMODE_BYTE(바이너리 방식)
PIPE_READMODE_MESSAGE(텍스트 방식)
함수 리턴방식
PIPE_WAIT(블로킹)
PIPE_NOWAIT(논블로킹 쓰지않음)
lpMaxCollectionCount : 서버로 데이터를 보내기에 앞서서 버퍼링할 수 있는 최대 바이트 크기. 서버와 클라이언트가 같은 PC일 경우 NULL전달
lpCollectDataTimeOut : 서버로 데이터를 보내기에 앞서서 버퍼링을 허용하는 최대 시간. 서버와 클라이언트가 같은 PC일 경우 NULL전달
HANDLE CreateFile(
LPCTSTR lpFileName,
DWORD dwDesireAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
함수 실패시 반환값은 INVALID_HANDLE_VALUElpFileName : 개방할 파일 이름
dwDesireAccess : 읽기/쓰기 모드지정
GENERIC_READ : 읽기 모드
GENERIC_WRITE : 쓰기 모드
dwShareMode : 파일 공유방식 지정
0 : 다른 프로세스에 공유 불가. 이미 개방된 파일은 중복 개방 불가.
FILE_SHARE_READ : 다른 프로세스에서 이 파일에 동시 읽기 접근 가능
FILE_SHARE_WRITE : 다른 프로세스에서 이 파일에 동시 쓰기 접근 가능. 단 동시에 같은 영역에 데이터를 쓰는 문제를 피해야 함.
lpSecurityAttributes : 보안 속성 지정. 핸들을 자식 프로세스에게 상속할 것인지 말 것인지
dwCreationDisposition : 파일이 생성되는 방법 지정
CREATE_ALWAYS : 항상 새 파일을 생성
CREATE_NEW : 새 파일 생성. 같은 이름의 파일이 존재하면 생성 실패
OPEN_ALWAYS : 기존 파일 개방. 없으면 새로 생성
OPEN_EXISTING : 기존 파일 개방. 존재하지 않으면 함수 호출 실패!
TRUNCATE_EXISTING : 기존 파일의 내용 지우고 개방. 파일이 존재하지 않으면 호출 실패!
dwFlagsAndAttributes : 파일의 특성 정보를 설정. 기본적으로 FILE_ATTRIBUTE_NORMAL사용
hTemplateFile : 일반적으로 NULL
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumverOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
함수 실패시 반환값은 0hFile : 데이터를 읽을 파일의 핸들
lpBuffer : 읽어 들인 데이터를 저장할 버퍼(배열, 메모리)의 주소(포인터)
nNumverOfBytesToRead : 파일로부터 읽고자 하는 데이터의 크기를 바이트 단위로 지정
lpNumberOfBytesRead : 실제 읽어 들인 데이터 크기를 얻기 위한 변수 주소
lpOverLapped :
BOOL WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
함수 실패시 반환값은 0hFile : 데이터를 저장할 파일의 핸들
lpBuffers : 데이터를 저장하고 있는 버퍼(배열, 메모리)의 주소(포인터)
nNumberOfBytesToWrite : 파일에 저장하고자 하는 데이터 크기(바이트 단위)
lpNumberOfBytesWritten : 파일에 실제 저장된 데이터 크기를 얻기 위한 변수 주소
lpOverlapped
3. 프로세스 환경변수
프로세스 환경변수
프로세스별로 별도로 메모리 공간에 문자열 데이터를 저장하고 관리할 수 있도록 되어 있다.
문자열의 구조는 [key, value] 형태이며 이를 환경변수라 한다.
부모 프로세스는 자식 프로세스 생성 시, 자식 프로세스의 환경변수를 등록할 수도 있고, 그냥 부모 프로세스의 환경변수를 상속시킬 수도 있다.
환경변수를 등록할 때 사용하는 함수
BOOL SetEnvironmentVariable(
LPCTSTR lpName,
LPCTSTR lpValue
);
함수 실패시 반환값은 0lpName : Key에 해당하는 값을 지정. 이후에 Key를 통해서 value값을 참조 가능
lpValue : value에 해당하는 값을 지정
SetEnvironmentVariable() 를 통해서 등록한 환경변수를 참조할 때 사용하는 함수
DWORD GetEnvironmentVariable(
LPCTSTR lpName,
LPTSTR lpBuffer,
DWORD nSize
);
함수 실패시 반환값은 0
함수 성공시 lpBuffer에 저장된 문자열의 길이 반환lpName : key 전달. key에 해당하는 value를 얻게 된다,
lpBuffer : value 값을 저장하기 위한 메모리의 주소를 지정
nSize : lpBuffer가 가리키는 메모리의 크기
'운영체제' 카테고리의 다른 글
7장. 프로세스간 통신(IPC) 1 (0) | 2018.08.08 |
---|---|
6장. 커널 오브젝트와 오브젝트 핸들 (0) | 2018.08.08 |
5장. 프로세스의 생성과 소멸 (0) | 2018.08.08 |
4장. 컴퓨터 구조에 대한 두 번째 이야기 (0) | 2018.08.08 |
3장. 64비트 기반 프로그래밍 (0) | 2018.08.08 |