매핑된 shared memory segment를 attach하는 함수
void *shmat(int shmid, const void *shmaddr, int shmflg);
SHM_RND: shmaddr이 0이 아니고 사용자가 지정하였을 때 사용하는 flag
shmaddr이 SHMLBA의 배수이지 않으면 shmaddr보다 작은 주소 중에서 SHMLBA의 배수인 가장 가까운 memory 번지에 attach된다.
그렇지 않으면, page의 시작 위치 주소에 attach된다.
SHMLBA: shmat()에 대한 호출에서 첨부 주소를 명시적으로 지정할 때 호출자는 주소가 이 값의 배수인지 확인해야 한다. SHMLBA는 일반적으로 시스템 페이지 크기의 일부 배수
-- 주소는 페이지 정렬이 되어야하기 때문에
IPC_PRIVATE
유일한 ID를 가지는 IPC를 생성
IPC_PRIVATE는 일반적으로 IPC_CREATE와 함께 쓰임
IPC_CREATE만 쓸 때 key에 해당하는 메모리가 존재하지 않으면 새로 만들고, 존재하면 해당 공유 메모리 식별자를 가져옴
IPC_PRIVATE과 함께 쓰면 key에 해당하는 메모리가 이미 존재하면 -1을
return
-- 기존의 메모리에 접근하는 것을 방지하고 항상 새로운 메모리를 만들고자 할 때 사용
PC기법 중 하나인 메시지큐는 Data Structure 중 큐를 사용
기본적으로는 먼저온 메시지가 먼저 꺼내어진다.
메시지큐의 msgtype에 따라 특정 메시지 중 가장 먼저들어온 메시지도 받아올 수 있다.
이 메시지는 커널에서 보관하고 있으니 프로세스가 종료되어도 사라지지 않는다.
메시지 큐의 용량이 허용하는 한 메시지는 계속 큐에 쌓일 수 있다.
메시지를 얻어오는 쪽은 가장 메시지를 읽고 메시지큐에서 그 메시지를 삭제한다.
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>
메시지 큐 id 가져옴
int msgget(key_t key, int msgflg);
key: 메시지큐를 얻어올 때 사용하는 고유 key 값
msgflg:
메시지를 보냄
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid: 메시지 큐의 id
msgp: msgp는 void* 이나 우리는 구조체 형식으로 아래와 같이 정의해야함
struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ };
- mtype: 메시지의 타입, 이 값은 0보다 커야함
메시지큐의 msgbuf를 정의할때 long형의 mtype을 반드시 명시
이 mytype을 각각 다르게 줌으로써, 특정 프로세스에서 특정메시지를 참조할 수 있도록 만들수 있다. 예를 들어 A라는 프로세스가 A'라는 메시지 타입을 참조해야하고, B는 B'를 참조하도록 해야한다면, msgbuf를 만들 때 A'는 1 B'는 2 이런식으로 메시지ㅣ타입을 정의하고 A는 mytype가 1인것을 B는 mytype이 2인것을 가지고 가도록 하면된다.
(mytype을 이용해서 자신이 원하는 메시지에만 선택적으로 접근이 가능)- mtext: mtext은 실제 메시지 큐에 보낼 데이터
mtext와 같이 배열일 수도 있고, 구조체일 수도 있다.
msgsz: msgsz는 메시지 큐에 전송할 데이터의 사이즈
위의 msgbuf의 mtype멤버를 제외한 실데이터의 크기를 전달해야함
msgflg: 큐의 공간이 없을때 msgsnd의 동작은 blocking(큐의 공간이 생겨날때까지 기다리는 것)
return 성공시 msqid_ds 구조체 필드 값 변경
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages in queue */
msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
msqid_ds 구조체는 메타데이터같은 것인데 msgsnd를 성공적으로 호출하고 나면 아래와 같이 변경
msgsnd를 했다면 받는 역할을 하는 시스템 콜
메시지 큐 id의 메시지를 하나 읽고 그 메시지를 큐에서 제거
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msqid: 메시지큐 id
msgp: 읽어들인 메시지를 msgp가 가리키는 주소에 위치(쉽게말해 읽어온 메시지)
msgsz: 메시지를 읽을 크기(더 정확히는 msgbuf의 mtext 크기)
만약 읽어들인 메시지가 지정된 크기보다 크다면 msgflg에 따라 동작이 결정
만약 msgflg가 MSG_NOERROR라면 메시지를 읽어들이나 잘려서 읽히게 됩니다. MSG_NOERROR가 명시되어있지 않다면 메시지를 읽어오지 않고 msgrcv 시스템콜은 -1을 반환합니다.
msgtyp: 0, >0, <0으로 동작이 나뉨
msgtyp == 0 큐의 첫번째 메시지를 읽음
msgtyp > 0 그 값과 동일한 메시지 타입을 갖는 메시지를 반환
msgtyp < 0 msgtyp의 절대값 이하의 가장 작은 메시지를 읽음
msgflg:
메시지큐를 제어하기 위한 시스템 콜
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid : 메시지 큐 id
cmd : 제어할 command
buf: cmd로 IPC_STAT과 IPC_SET을 사용할때 전달, 필요없으면 NULL
메시지 큐 확인하기
ipcs -q
옵션으로 q 말고 다른 옵션을 부여하면
해당 명령어를 통해 메시지 큐 외에도 현재 구동중인 IPC 관련 정보를 볼 수 있다.
메시지 큐 삭제하기
ipcrm -q msqid
해당 msqid를 사용하는 메시지큐를 삭제