관리 메뉴

너와 나의 스토리

[Unix] CH.8 IPC (message queue, semaphores, shared memory) 본문

Unix/이론

[Unix] CH.8 IPC (message queue, semaphores, shared memory)

노는게제일좋아! 2019. 12. 8. 15:14
반응형

IPC (Inter-Process communication)

  • 같은 시스템 내의 프로세스들끼리 정보를 공유하는 메커니즘을 제공

* 외부 프로세스들끼리 통신은 소켓을 주로 사용

 

 

Permission structure

  • IPC 객체가 만들어지면, 시스템은 IPC facility의 status 구조체를 만든다.

  • effective user-id, group-id는 mode와 함께 접근 권한을 결정한다.
  • umask 값은 IPC facility가 만들어질 때 영향을 미치지 않는다.
  • msgctl, semctl, shmctl을 호출해서 udi, gid, mode를 수정할 수 있다.

 

 

Identifiers and Keys

  • Key
    • IPC 객체의 외부 이름
    • IPC 구조가 만들어질 때마다(msgget, semget, shmget을 호출함으로써), key가 지정된다.
    • 원시 시스템 데이터 타입 key_t, <sys/types.h> -> long integer
  • Identifier
    • IPC 객체의 내부 이름 -> 모든 프로세스가 공유 가능
    • 음이 아닌 정수
    • get 연산의 결과
    • 약간 파일 디스크립터 느낌
      • 파일 디스크립터와 달리 IPC facility identifier은 유일하다.

 

 

ftok( ) system call

  • ftok(): path와 id를 key_t 값으로 변환한다. -> IPC key 값 얻음
  • 인자
    • path: 존재하는 파일
    • id: id의 하위 8 bits만 사용됨
  • path와 id의 결합은 IP 객체의 유일한 식별자가 됨

 

Generating IPC indentifier from IPC keys

 

 

 

shell에서 IPC resources에 접근하기

 

 

Pipe FIFO Message queue
부모 자식 프로세스간에 temporary하게 통신 permanent하게 통신 permanent하게 통신
first-in-first-out first-in-first-out first-in-first-out 아닐 수 있음
  외부에 존재하는 파일  
fork()한 부모 자식 프로세스끼리만 사용 가능 모든 프로세스 사이에서 통신 가능 아무 프로세스나 사용 가능
(하나의 파이프로)읽고 쓰기 동시에 불가 (단방향 흐름만 가능) (하나의 FIFO로)읽고 쓰기 동시에 불가 (단방향 흐름만 가능)  

 

 

 

Message Queue

  • 프로세스들끼리 메시지 주고받음
  • 메시지의 linked list를 kernel에 저장하고 message queue identifier로 식별한다
    • 메시지 큐는 프로그램의 메모리에서 관리하는 것이 아니라 커널 메모리에서 관리하므로, 프로그램이 종료해도 메시지 큐가 사라지지 않는다. 
    • 커널 내에서 msqid_ds 형태로 관리됨

 

 

msgget() system call

  • msgget(): key 파라미터와 연결된 메시지 큐 식별자를 리턴

  • IPC_PRIVATE: 시스템이 알아서 key 값을 만들어줌
  • PERMS: identifier num이 리턴됨 (unique)

  • IPC_CREAT: 메시지 큐를 새로 생성하기 위해 사용. 만약 이미 key가 있다면 해당 메시지큐의 식별자를 되돌려 줌
  • IPC_EXCL: IPC_CREAT과 같이 쓰이며, IPC_EXCL이 지정되어 있을 경우, 이미 key로 존재하는 메시지큐가 있다면, -1을 리턴하고 errno를 세팅

message queue의 메시지 구조체

 

 

 

 

msgsnd() system call

  • msgsnd(): 프로그램은 큐에 메시지를 넣는다.
  • 메시지는 항상 큐의 끝에 놓인다
  • 인자:
    • ptr: 사용자가 정의한 버퍼를 가리킴
    • nbytes: mtext 사이즈
    • flag: 만약 IPC_NOWAIT이 지정되지 않았다면, 큐에 빈 공간이 생길 때까지 블락됨.

 

 

msgrcv() system call

  • 인자:
    • ptr: 사용자가 지정한 버퍼를 가리킴
    • nbytes: mtext 사이즈
    • flag: IPC_NOWAIT, MSG_NOERROR
      • 만약 반환된 메시지가 nbytes보다 크고, flag의 MSG_NOERROR bit가 set 되어 있다면, nbytes 이후의 메시지는 잘린다. (버려짐)
      • 만약 메시지가 너무 크고, flag 값이 지정되지 않았다면, E2BIG의 에러가 대신 리턴된다.

  • type==0 : 메시지 큐에서 첫 번째 메시지를 받아온다.
  • type>0 : 메시지 큐에서 주어진 type과 동일한 메시지를 받아온다.
  • type<0 : 주어진 type보다 작은 type의 메시지들 중 가장 작은 type을 갖는 메시지를 받아온다.
  • 프로세스가 메시지 큐에서 메시지를 읽으면 커널은 읽은 메시지를 삭제하는 형태이므로, 하나의 메시지는 한 개의 프로세스만 받을 수 있다.

 

msgctl() system call

  • msgctl(): msqid로 지정된 메시지 큐의 permission을 바꾸거나 할당 해제한다.

  • 프로그램 종료돼도 메시지 큐는 없어지지 않으므로 IPC_RMID 명령어를 이용해 지워줘야 한다.

 

 

 

 

Semaphore

  • 세마포어는 wait과 signal을 가지는 정수 변수이다.
    • wait: down, P, lock  -> semaphore 값 -1
    • signal: up, V, unlock, post   -> semaphore 값 +1

  • 각 세마포어의 요소에는 최소한 다음 정보들이 포함된다
    • semval: 음이 아닌 정수로 나타내는 세마포어의 값
    • sempid: 세마포어 요소를 조작한 가장 최근 프로세스의 ID
    • semncnt: 세마포어 값이 증가하기를 기다리는 프로세스의 수
    • semzcnt: 세마포어 값이 0이 되길 기다리는 프로세스의 수
      • 세마포어의 값이 0이 되면, 큐이 있는 프로세스는 깨어난다
  • 각 세마포어 요소는 두 개의 큐를 가진다
    • 세마포어 값이 0이 되길 기다리는 프로세스들의 큐
    • 세모 포아 값이 증가되길 기다리는 프로세스들의 큐

 

 

 

semget() system call

  • key와 관련된 세마포어의 식별자를 반환
  • 인자:
    • nsems: 집합 안에 있는 세마포어 요소들의 수
      • nsems==0 : 기존에 있는 것을 참조하겠다는 뜻

 

 

 

semctl() system call

  • 세마포어 집합의 각 요소들은 사용 전에 cemctl()로 초기화되어야 한다.
  • 인자 - cmd 값에 따라 다름
    • cmd로 몇 개를 초기화할지 결정함

 

 

semop() system call

  • semop(): 식별자 semid와 연관된 세모포어 집합에 대해 사용자 정의 세마포어 연산의 집합을 자동적으로 수행한다.
  • nops: 여러 개의 세마포어의 값을 동시에 변경하려고 할 때 사용

  • sem_num: 다루고자 하는 세마포어 번호
  • sem_op: 수행할 동작 (양수, 음수, 0)
    • 음수: 세마포어로 값으로부터 그 값을 뺀다. 
    • 양수: 세마포어로 값에 그 값을 더한다
    • 0: 호출한 프로세스는 세마포어의 값이 0이 될 때까지 기다림.
  • sem_flg: 동작 플래그
    • SEM_NOWAIT: 세마포어 호출 즉시 실행하지 못했을 경우(세마포어 값이 0이 되면 원래 wait을 하는데), 기다리지 않고 실패로 바로 리턴함.
    • SEM_UNDO: 프로세스가 종료되면 시스템에서 세마포어 설정을 원래 상태로 되돌림.
      • 세마포어 할당 해제 안 하고 프로그램 종료하는 것 예방

 

 

 

semop(): SEM_UNDO

  • 프로세스에 세마포어를 통해 할당된 리소스가 있는데, 프로세스가 종료된다면 문제가 된다.
  • 세마포어 연산에 SEM_UNDO flag를 지정하고 자원을 할당함(sem_op 값이 음수)
  • 커널은 특정 세마포어로부터 할당된 자원이 몇 개인지 기억한다 (sem_op의 절댓값)
  • 프로세스가 자발적으로 또는 비자발적으로 종료되면, 커널은 프로세스에 미해결 세마포어 조정이 있는지 확인하고, 해당하는 경우 해당 세마포어에 조정을 적용
  • 즉, 어떤 프로세스가 lock하고 들어가서(p연산), v연산 전에 죽을 경우, v 연산을 기다리는 다른 프로세스들은 영원히 lock된다. SEM_UNDO는 이를 예방할 수 있다.

 

 

 

Shared Memory

  • shared memory는 여러 프로세스들이 같은 메모리 세그먼트에서 읽고, 쓰기를 허락한다.
  • 클라이언트와 서버 사이에 데이터 카피가 필요 없기 때문에, IPC보다 빠른 형태이다.
  • 만약 서버가 공유 메모리 영역에 데이터를 놓으면, 클라이언트는 서버가 작업(쓰는 중)을 끝날 때까지 그 데이터에 접근 할 수 없다.
    • 세마포어는 공유 메모리 접근 동기화를 위해 사용된다.
    • 이는 사용자가 직접 공유 메모리에 접근 제어를 해줘야한다 (세마포어 등을 사용해서)

 

 

 

 

shmget() system call

  • 인자:
    • size: 메모리 세그먼트의 최소 크기(in bytes) 

 

 

 

shmat() system call

  • shmat(): shmid로 지정된 공유 메모리 세그먼트를 호출 프로세스의 주소 공간에 첨부하고 shmid에 대한 shm_nattach 값을 증가시킨다.
    • 즉, 공유 메모리를 쓰고 싶은 프로세스는 이를 자신이 주소 공간에 첨부한 다음에 자기 메모리처럼 사용함.
  • 인자: addr
    • addr이 0이라면, 세그먼트는 커널이 선택한 첫 번째 사용 가능한 주소에 연결된다. 
      • ㄴ권장되는 기술
    • addr이 0이 아니고, SHM_RND가 지정되지 않으면 세그먼트는 addr에 의해 주어진 주소에 첨부된다.
    • addr이 0이 아니고, SHM_RND가 지정되면 세그먼트는 (addr - (addr%SHMLBA))에 의해 주어진 주소에 첨부된다.
      • SHM_RND 명령은 "round"를 나타낸다. -> 반올림 
      • SHMLBA는 "low boundary address multiple"를 나타내며 항상 2의 거듭 제곱이다.

 

 

 

shmdt() system call

  • addr 인자는 이전에 shmat 호출하면서 반환 받은 값이다. (공유 메모리 세그먼트 포인터)
  • 성공하면, shmdt는 shmid_ds 구조체와 연관된 shm_nattch 카운터-1

 

 

shmctl() system call

  • cmd 인자는 shmid에 의해 지정된 세그먼트에서 수행될 다음 5가지 명령 중 하나를 지정한다.

  • SHM_LOCK, SHM_UNLOCK -> 슈퍼유저에 의해서만 실행되는 명령어

 

 

 

 

 

 

 

 

 

 

 

 

출처: [UNIX system programming]

 

 

반응형
Comments