![시스템 V IPC (System V) 1 -Infinite](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSULhF%2FbtrFkZUEux9%2FHgxIZfK1ZFbZLpEcHo97bK%2Fimg.png)
이번 포스팅은 System V IPC 기법들에 대하여 알아보도록 하겠습니다.
System V에서는 메시지 큐, 공유 메모리 기법을 통해 프로세스 간 통신을 진행 할 수 있습니다.
독립적인 프로세스들이 서로 통신을 함에 있어 Critical section(중요한 데이터 영역)에 동시에 진입할 경우 Race Condition(충돌)이 발생 할 수 있습니다. 이를 막기위해 독립적인 프로세스들은 동기화 과정이 필요한데 세마포어가 해결을 도와줄 수 있습니다. -> 세마포어는 단순히 메모리 영역에 접근할 수 있는 프로세스들을 알려주는 역할이며 이는 통신기법이 아닌 동기화기법에 해당합니다.
또한 이번 챕터에서 다룰 통신기법들은 각각 공통된 키 생성 -> 키를 통한 식별자 생성 과정을 거친 후 제공되는 함수들을 사용하여 통신을 할 수 있습니다.
● System V
-> 시스템 V에서 제공되는 프로세스 간 통신 방법으로는 메시지 큐, 공유 메모리, 세마포어 3가지가 있습니다.시스템 V IPC를 이용하려면 IPC 객체를 생성해야 합니다. 이를 위해 공통으로 사용되는 요소로는 키와 식별자가 있습니다.키를 생성하는 방법에는 두가지 방식이 있습니다.
1. ftok(*pathname, int proj_id) // 임의의 파일 경로명, 임의의 번호(1~255)
2. IPC_PRIVATE // 임의의 키 값
같은 키로 생성된 식별자만 통신에 사용이 가능함으로 미리 정해진 키를 서버와 클라이언트 프로세스가 공유할 수 있게 해줘야 합니다.
● 메시지 큐
-> 메시지 큐는 파이프와 유사합니다. 단, 파이프는 스트림 기반으로 동작하고, 메시지 큐는 메시지 단위로 동작 합니다.
-> 각 메시지에는 메시지 유형이 있으므로 수신 프로세스는 어떤 유형의 메시지를 받을 것인지 선택할 수 있습니다.
● 메시지 큐에서 제공되는 함수
- 식별자 생성 : msgget(key, msgflg); // key는 사전에 생성한 key값, msgfla는 속성 플래그이며, 보통 IPC_CREAT를 사용합니다.
- 메시지 전송 : msgsnd(식별자, 메시지 버퍼주소, 메시지 크기, msgflg);
- 메시지 수신 : msgrcv(식별자, 메시지 버퍼주소, 버퍼 크기, 메시지 유형, msgflg);
- 메시지 제어 : msgctl(식별자, 수행할 기능, 메시지 큐 구조체 주소) // 보통 IPC 객체를 해제할 때 주로 사용합니다.
msgfla에는 블록 모드(0) / 비블록 모드(IPC_NOWAIT)가 있으며 둘의 차이는 메시지 큐가 가득 차있을 경우 기다리느냐 / 오류를 바로 리턴 하느냐의 차이입니다.
또한 메시지를 담고 있는 메시지 버퍼는 msgbuf 구조체를 사용하여 정의를 합니다. 이 구조체에는 int mtype(메시지 유형), char mtext[n](메시지 내용이 저장될 메모리) 두 개의 변수가 존재합니다.
● 메시지 큐 예제
이렇게 제공되는 각각의 함수를 눈으로만 보면 이해가 잘 되지 않을테니 예제를 통해 확인을 해보도록 합시다.
아래 예제는 send측에서 메시지 큐를 생성하여 메시지를 담고, receive 측에서는 각각의 메시지 유형에 맞는 메시지만을 수신하는 프로그램입니다.
/* msgq_send.c */ include <sys/msg.h> #include <stdlib.h> #include <stdio.h> #include <string.h> // 메시지 버퍼 구조체 struct mymsgbuf { long mtype; char mtext[80]; }; int main(int argc, char * argv[]) { key_t key; int msgid, i; long mtype; struct mymsgbuf mesg; // 키 생성과 동시에 메시지 큐 식별자 생성 key = ftok("keyfile", 1); msgid = msgget(key, IPC_CREAT|0644); if (msgid ==-1) { perror("msgget"); exit(1); } i = atoi(argv[2]); // 커맨드라인으로 메시지 유형값을 받아옴 if(i%2 == 0) { // 받아온 값이 짝수라면 mesg.mtype = 4; } else { //받아온 값이 홀수라면 mesg.mtype = 3; } strcpy(mesg.mtext, argv[1]); //mesg 구조체의 mtext멤버에 argv값을 copy //메시지 송신 if (msgsnd(msgid, (void *)&mesg, 80, IPC_NOWAIT) ==-1) { perror("msgsnd"); exit(1); } return 0; } |
위의 소스코드는 메시지를 송신하는 프로세스입니다. 메시지 유형을 실행할 때 받아오도록 구현하였습니다.
/* msgq_recv_even.c */ // 메시지 유형이 짝수인 경우에만 수신하는 프로세스입니다. #include <sys/msg.h> #include <stdlib.h> #include <stdio.h> // 메시지 버퍼 구조체 struct mymsgbuf { long mtype; char mtext[80]; }; int main(int argc, char* argv[]) { struct mymsgbuf inmsg; key_t key; int msgid, len; int x; // 수신측 또한 동일한 키를 생성하고 식별자를 얻음 key = ftok("keyfile", 1); if ((msgid = msgget(key, 0)) < 0) { perror("msgget"); exit(1); } // 메시지 유형이 4인 메시지만을 수신. IPC_NOWAIT로 메모리가 비어있을 경우 기다리지 않고 -1을 return if(len = msgrcv(msgid, &inmsg, 80,4 , IPC_NOWAIT) == -1) { msgctl(msgid, IPC_RMID, (struct msgid_ds*)NULL); //msgctl을 이용하여 IPC 객체를 삭제 exit(0); } else { // 메시지 수신이 된 경우 printf("Received Msg = %s, Len=%d\n", inmsg.mtext, len); } msgctl(msgid, IPC_RMID, (struct msgid_ds*)NULL); return 0; } |
/* msgq_recv_odd.c */ // 메시지 유형이 홀수인 경우에만 수신하는 프로세스입니다. #include <sys/msg.h> #include <stdlib.h> #include <stdio.h> struct mymsgbuf { long mtype; char mtext[80]; }; int main(int argc, char* argv[]) { struct mymsgbuf inmsg; key_t key; int msgid, len; int x; key = ftok("keyfile", 1); if ((msgid = msgget(key, 0)) < 0) { perror("msgget"); exit(1); } // 메시지 유형이 3인 경우에만 수신. len = msgrcv(msgid, &inmsg, 80, 3, 0); printf("Received Msg = %s, Len=%d\n", inmsg.mtext, len); // 수신이 끝난 뒤 메모리 해제 msgctl(msgid, IPC_RMID, (struct msgid_ds*)NULL); return 0; } |
이제 위의 소스코드에 대한 결과를 확인해 보도록 합시다.
위 결과값은 짝수 메시지 유형으로 ByeBye라는 메시지를 송신한 뒤 수신하는 결과값입니다.
위 결과값은 홀수 메시지 유형으로 Hello라는 메시지를 송신한 뒤 수신하는 결과값입니다.
이렇게 메시지 큐를 이용한 예제를 확인하면서 볼 수 있듯 메시지 큐는 단방향이며, 그때 그때 메시지 큐를 생성한 뒤 메시지를 주고 받습니다. 이는 Message Passing 방법의 일종이며 특징으로는 동기화 과정이 필요없지만 메시지 큐 생성 및 메시지 copy로 인한 추가적인 오버헤드가 발생하여 Shared Memory에 비해 효율적이진 못하다는 점입니다.
다음 포스팅에서는 Shared Memory와 Message Passing에 관한 차이를 간단하게 알아보고 Shared Memory에 대한 소개를 드리려 합니다.
'CS > 시스템 프로그래밍' 카테고리의 다른 글
Semaphore(System V vs POSIX) -Infinite (0) | 2022.06.21 |
---|---|
시스템 V IPC (System V) 2 -Infinite (0) | 2022.06.21 |
파이프(PIPE) -Infinite (0) | 2022.06.20 |
시그널(signal) -Infinite (0) | 2022.06.20 |
쓰레드(Thread) -Infinite (0) | 2022.06.20 |
개발 기술 블로그, Dev
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!