본문 바로가기
컴퓨터 기초/운영체제 실습

19.메시지큐, 공유 메모리, 세마포어 - ipc

by 인생여희 2020. 7. 21.

#.키와 식별자

시스템 V IPC를 사용하려면 IPC의 객체를 생성해야 하는데, 이를 위해 공통적으로 사용하는 기본 요소가 키와 식별자이다.

 

#.키생성 방법

-키로 IPC_PRIVATE를 지정한다 IPC_PRIVATE를 키로 지정해 생성된 식별자를 서버와 클라이언트 모두 알 수 있게 해야 한다. fork 함수로 생성된 부모-자식 프로세스 간 통신에서 유용하게 사용할 수 있다. 

 

-ftok 함수로 키를 생성한다. ftok 함수는 경로명과 숫자값을 받아서 키를 생성한다. 따라서 서버와 클라이언트가 같은 경로명과 숫자값을 지정하면 공통 식별자를 생성할 수 있다.

 

*상수 :  IPC_PRIVATE

*키 생성 : key_t ftok(const char *path, int id);

*IPC 정보 검색 : ipcs [-aAbciJmopqstZ] [-D mtype]

*IPC 삭제 : ipcrm [-m shmid] [-q msqid] [-s semid] [-M shmkey] [-Q ,sgleu] [-S semkey]

 

키 생성하기 : ftok(3)

#include <sys/ipc.h>

key_t ftok(const char *path, int id);

ftok 함수는 path에 지정한 경로명과 id에 지정한 정수값을 조합해 새로운 키를 생성한다. 경로명은 파일시스템에 존재해야 한다.

 

#.IPC 공통 구조체

IPC에서 공통으로 사용하는 IPC 공통 구조체는 <sys/ipc.h> 파일에 정의되어 있다. 

struct ipc_perm {

    uid_t   uid;    // 구조체의 소유자 ID를 의미한다.

    gid_t   gid;    // 구조체의 소유 그룹 ID를 의미한다.

    uid_t   cuid;   // 구조체를 생성한 사용자 ID를 의미한다.

    gid_t   cgid;   // 구조체를 생성한 그룹 ID를 의미한다.

    mode_t  mode;   // 구조체에 대한 접근 권한을 의미한다.

    uint_t  seq;    // 슬롯의 일련번호를 의미한다.

    key_t   key;    // 키값을 의미한다.

    int     pad[4]; // 향후 사용을 위해 예약되어 있는 영역이다.

}

 

#.시스템 V IPC 정보 검색

시스템 V IPC의 정보를 검색하고 현재 상태를 확인하는 명령은 ipcs이다. ipcs 명령을 실행하는 동안에도 IPC의 상태가 변경될 수 있음.

 

#.시스템 V IPC 정보 삭제

불필요한 IPC 객체를 삭제하려면 ipcrm 명령을 사용

 

#.메시지큐

메시지 큐는 파이프와 유사한데 단, 파이프는 스트림 기반으로 동작하고, 메시지 큐는 메시지(또는 패킷) 단위로 동작한다.

 

*메시지 큐 생성 : int msgget(key_t key, int msgflg);

*메시지 전송 : int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

*메시지 수신 : ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg);

*메시지 제어 : int msgctl(int msqid, int cmd, struct msqid_ds *buf);

 

 

#.메시지큐 수행결과

msgsnd 함수의 수행이 성공하면 msqid_ds 구조체의 항목에서 msg_qnum 값이 1 증가하고, msg_lspid는 msgsnd 함수를 호출한 프로세스의 ID로 설정됩니다. msg_stime은 현재 시각으로 설정됩니다. msgsnd 함수는 수행을 실패하면 -1을 리턴하고 메시지는 전송하지 않습니다.

 

#.공유메모리

메모리의 일부 공간을 두 독립적인 프로세스에서 공유하고, 해당 메모리를 통해 데이터를 주고받을 수 있다.

 

*공유 메모리 생성 : int shmget(key_t key, size_t size, int shmflg);

*공유 메모리 연결 : void *shmat(int shmid, const void *shmaddr, int shmflg);

*공유 메모리 해제 : int shmdt(char *shmaddr);

*공유 메모리 제어 : int shmctl(int shmid, int cmd, struct shmid_ds *buf);

 

 

#.세마포어

세마포어는 프로세스 사이의 동기를 맞추는 기능을 제공해준다. 공유 메모리에 여러 프로세스가 동시에 쓰기를 시도하면 데이터가 손상되는 현상이 발생하므로, 여러 프로세스 사이에서 동작의 순서를 지정해줘야 한다.

 

*세마포어 생성 : int semget(key_t key, int nsems, int semflg);

*세마포어 제어 : int semctl(int semid, int semnum, int cmd, ...);

*세마포어 연산 : int semop(int semid, struct sembuf *sops, size_t nsops);

 


 

#.메시지큐 생성+전송 예제

결과

메시지큐가 생성되었다.

 

 

#.메시지큐 받기 예제

결과

위의 예제에서 메시지큐에 저장한 Message Q Test라는 글자를 받았다.

 

 

#.메시지큐 제거 예제

결과

아래 메시지큐가 비어있는것을 알 수 있다.

 

 

#.공유메모리 생성 예제

결과

공유메모리가 생성되었다.

 

 

#.부모 프로세스와 자식 프로세스 사이에서 공유 메모리를 사용해 데이터를 주고 받는 예제

결과

자식프로세스에서 공유메모리에 쓰고, 부모프로세스에서 읽었다.

 

 

#.독립적인 프로세스 사이에서 공유 메모리를 사용해 데이터를 주고 받는 예제

-서버

-클라이언트

결과

 

#.세마포어 예제

결과

각각의 스레드가 공유자원에 한번씩 순차적으로 접근을 한다.  semop 함수를 주석처리해서 실행하면 동기화가 되지 않는 현상이 나타난다.

 

 

 

 

 

 

출처: 유닉스 프로그래밍 (한빛미디어) , joinC