본문 바로가기

CS/유닉스프로그래밍

11. 유닉스 IPC - IO multiplexing

I/O multiplexing

fifo 사용할때는 fifo 하나를 두고 서버 rcv 있고 send 가 여러개 있음

fifo를 보내면 여러개 프로세스 간에 interleaving은 안됨. pipe 에서는 안됨,
그래서 하나가 보내면 순서 관계는 잘 맞춰짐 그래서 동시에 보내더라도 먼저 도착하는게 순서대로 들어옴 
그럼 receive는 하나씩 가져오면 됨. 

 

근데 문제는 통신 채널이 하나임. 이 통신채널이 client가 여러개 있고
receive 할때 서버가 채널이 각각 데이터를 통신하는 채널이 각각 다른 여러개가 있을때
이걸 어떻게 manage하느냐 이거임. 

 

 

이게 돌다가 하나가 비어있어서 block 되면 다른 쪽을 보지를 못함

이런 문제가 있어서 이런 경우 어떻게 처리하느냐가 io multiplexing 임

 

해결하는 방법으로 non block 하는 방법이 있음 blocking 하면 다른데 체크 못함
non blocking 하면 문제는 뭐냐면 채널이 여러개일때 계속 왔다갔다 하면서 계속 루프를 돌아야함
cpu time이 100%가 됨 wastiing 됨 그래서 해법이 될수 없음
그래서 해법이 multi plexing io model 이라는 거임 

 

The select(2) system call

#include <sys/time.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
			fd_set *exceptfds, struct timeval *timeout);
// returns : count of ready descriptors, 0 on timeout, -1 on error

 

nfd는 파일디스크립터가 아니라 파일디스크립터 갯수임, 엄밀히 갯수는아니고 가장 높은 파일디스크립터 번호를 말함

파일디스크립터가 3,4 open 되어있다면 nfds는 5가 됨.

readfds는 멀티플렉싱에서 기다리는 read를 하는 파일디스크립터들의 array임 포인터로 되어있음
writefds는 write하기 위한 파일디스크립터의 array 
exceptfds는 예외처리를 하기 위한거임 에러처리를 위한 파일디스크립터
timeval은 timeout을 setting 하는거임 무한정 기다릴 수 없기 때문에

 

struct timeval {
		long tv_sec;
        	long tv_usec;
};

sec은 초단위고 usec은 마이크로sec 단위임 1/1000초 단위로 타임을 설정할 수 있음

만약 timeout 변수가 null 값을 가지면 wait forever영원히 기다리는 거임

 

select에서 기다리다가 데이터를 읽을 준비가 되어있거나 write할 준비가 되면 딱 깨어나는 거임
select가 return을 디스크립터가 io할 준비가 그 중 하나라도 io할 준비가 되어있으면 깨어나는 거임
또는 signal이 와서 catch 가 되면 깨어나는 거임

 

구체적으로 sec과 usec에 0이라고 지정을 해두면 null과 다름. 이 포인터에다가 0을 주는 거임
이걸 가리키는 메모리가 없는거임. 이걸 가리키는 메모리가 있음. 거기에 0이 들어감

 

모든 지정된 디스크립터가 test되고, 즉각 return 되어야하는데 이미 io 준비가 된 것이 있으면 거기에 대해 io
각각 0이 아니고 무슨 값을 준다면 timout 기다리는거임. 주어진 시간이 있는거임

이 시간동안 기다림 - 파일디스크립터가 io를 준비할 때까지 기다림. 이 시간동안 read된게 없으면 timeout 됨

 

timeout 되기 전에 io 할 준비가 되는게 적어도 하나가 있으면 0이 return 됨 
select가 return 되는 경우는 time out이 되는 경우, 아니면 timeout 전에 디스크립터 io 준비가 됐는지임
select return 값으로 그걸 구분함 0이면 timeout 된거임, 만약 io할 준비가된 디스크립터의 리턴되는 경우도 있음

 

timeout == NULL

wait forever. Return is made when one of the specified descriptors is ready or when a signal is caught.

timeout->tv_sec==0&& 
timeout->tv_usec==0

Don’t wait all. All the specified descriptors are tested, and return is made immediately.

timeout->tv_sec!=0||
timeout->
tv_usec!=0

Wait the specified number of seconds and microseconds. Return is made when one of the specified descriptors is ready or when the timeout value expires. If the timeout expires before any of the descriptors is ready, the return value is 0.

 

#include <sys/select.h>

int FD_ISSET (int fd, fd_set *fdset);
// returns : nonzero if fd is in set, 0 otherwise

 

s는 set임 
set이 쭉 있는데, fd_set으로 포인터로 값을 변경해야하니까 포인터를 이용해서 씀
isset몇번째 set이 있는지 확인해보는거임 true면 setting 이 되어있고 false면 아니라는 말임
특정 디스크립터를 clear나 set할 수 있음 특정 비트, 특정 파일디스크립터를
_zero는 모든 파일디스크립터를 0으로 만드는 거임

 

 

 

fd_set rset; 
int fd; 

FD_ZERO(&rset); 
FD_SET(fd, &rset);
FD_SET(STDIN_FILENO, &rset); 


if (FD_ISSET(fd, &rset)) {
       ...
}

 

fd_set readset, writeset;

FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_SET(0, &readset);
FD_SET(3, &readset);
FD_SET(1, &writeset);
FD_SET(2, &writeset);
select(4, &readset, &writeset, NULL, NULL);

 

 

rset이 파일디스크립터 set인데 값을 변환해야하니까 포인터로 함
모두 0으로 만들고, 그 중 원하는 파일디스크립터를 set해주는 거임
여기에 stdin파일넘버로 하면 0임 0번 파일디스크립터를 set해주는 거임
오른쪽은 그냥 사용되는 예임
맨 마지막 예는 두번째 null로 해서 wait forever

 

return -1 하면 error 발생한거임. 

signal 을 받은 거면 interrupt 해서 서비스 루틴 실행해서 실패
io할거를 기다리는 파일디스크립터에다가 set을 먼저함.  
0인 경우는 어떤 파일디스크립터도 준비되지 않음
positive라는 건 어떤 숫자인데 ready가 된 디스크립터의 갯수가 나온거임


그 디스크립터의 sum은 all three set임 readfds writefds exceptfds이걸 다더한게 return 되는 거임
같은 디스크립터에 대해서 read와 write가 겹쳐지면 곤란할수잇음 근데 안되는건 아니고 되도록 그렇게 하면 안좋음
근데 같은 파일디스크립터에 read write 있어도 작동안하는건아니지만 곤란함


ready 되는 것은 그대로 1이 되어잇고 그게 아니면 0으로 다 clear가 됨 아까 말한거 잘못했다고 함
ready 가 된게 1로 그대로 남아있고 ready 가 아닌거 0으로 clear

 

#include <sys/time.h>
#include <sys/wait.h>
#define MSGSIZE   6

char *msg1 = "hello";
char *msg2 = "bye!!";
void parent(int [][]);
int child(int[]);

main(){
  int pip[3][2];
  int i;

  for (i = 0; i < 3; i++){
    if (pipe(pip[i]) == -1) fatal ("pipe call");
    switch (fork()){
    case -1:  /* 오류 */      fatal ("fork call");
    case 0:   /* 자식 */
      child (pip[i]);
    }
  }
  parent (pip);
  exit (0);
}

 

parent가 pipe를 세개를 만듦 그리고 child 를 세개를 만듦 child1 ch2 ch3 이렇게 각각 child 가 pipe에다가 write함

 

 

void parent(int p[3][2]){
  char buf[MSGSIZE], ch; fd_set set, master;   int i;
  for (i = 0; i < 3; i++)  close (p[i][1]);

  FD_ZERO (&master);
  FD_SET (0, &master);
  for (i = 0; i <3; i++) FD_SET (p[i][0], &master);

  while (set = master, select (p[2][0]+1, &set, NULL, NULL, NULL) > 0){
    if (FD_ISSET(0, &set)){
      printf ("From standard input...");
      read (0, &ch, 1);
      printf ("%c\n", ch);
    }

    for (i = 0; i < 3; i++){
      if (FD_ISSET(p[i][0], & set)){
        if (read(p[i][0], buf MSGSIZE)>0){
          printf ("Message from child%d\n", i);
          printf ("MSG=%s\n",buf);
          }
      }
    }
    if (waitpid (-1, NULL,WNOHANG) == -1) return;
  }
}

int child(int p[2]){
  int count;
  close (p[0]);

  for (count = 0; count < 2; count++)
  {
    write (p[1], msg1, MSGSIZE);
    sleep (getpid() % 4);
  }

  write (p[1], msg2, MSGSIZE);
  exit (0);
}

 

child를 먼저보면 child 는 부모가 만들면 이때 여기서 pipe를 받아가지고 child 는 write를  0 1 하고 두번하고

밑에 한번 더해서 총 세번함 근데 중간에 시간간격을 두는데 getpid 함

345678 뭐이걸 4 나눈 나머지 0123중에 하나가 나옴. 

그러면 시간이 0123중 하나가 나옴 랜덤하게 나옴 그만큼 시간 간격 두고 write가 일어남 

parent를 보면 child 의 모든 파일디스크립터를 다 가지고 와서 파일디스크립터에 대해서 parent는 read만함 
write는 전부 닫아야함 안쓰니까. 


0번만 set을 함 나머지는 0임 그리고 master에서 파일디스크립터 0에 해당하는거만 set을 함 
그러면 3 5 7이 set됨 0은 키보드니까 set됨 child의 pipe 중 read만 set을 한 거임 나머지는 clear해둠 
그래서 처음에 자기가 받으려고 하는 파일디스크립터 키보드를 포함해서 
그리고 child 가보내는 각각의 pipe 에있는거에대해서도 받아야함 , 

데이터를 보낸거 말고 나머지는 clear되니까 그 master값을 set에 저장해놓음. 

read file descriptor임 다 null로 함 


p[2][0]이건 7이라서 +1 하면 8임 parent 는 7까지만 쓴다는 말임 parent 입장에서는 8빼도 상관없음 
select가 무조건 assign 처음에 하니까 set=master하고 while의 조건은 그 select가 됨


0이면 timeout -1이면 signal 받은거고 0초과면 set에서 1로 set되어있는 디스크립터중 하나가 준비가 되어있는거임 
키보드에서 입력이 들어왔을 수도 있어서 그걸 체크해야함 그럼 키보드(0번)에서 읽음
그게 아니면 어느게 들어와있는지 체크함 들어온건 set에있고 나머지는 0으로 되어있음 

거기서 read해서 출력 다하고 난다음에 waitpid WNOHANG  

모든 child 에 대해서 기다리는데 기다리지 말라니까 즉각 return 됨


-1 모든 child 에 대해서 기다리는 거임, -1이 return 되면 child 가 하나도 없을 때임 
child 가 모두 exit 했을 때, -1이 떠서 return 함 하나라도 있으면 0이 return 돼서

child가 still running 이라서 if 문 false 다시 while 문 돎

 

 

int join (char *com1[], char *com2[]){
  int p[2], status;
  
  switch (fork()){
  case -1: fatal ("1st fork call in join");
  case 0: break;
  default: wait(&status); return(status);
  }
  if (pipe(p) == -1) fatal ("pipe call in join");

  switch (fork()){
  case -1: fatal ("2nd fork call in join");
  case 0:
    dup2 (p[1],1); /*표준 출력이 파이프로 가게 한다*/
    close (p[0]);  /*화일 기술자를 절약한다. */
    close (p[1]);
    execvp (com1[0], com1); /* com1: ls */
    fatal("1st execvp call in join");
  default:
    dup2(p[0], 0); /* 표준 입력이 파이프로부터 오게 한다 */
    close (p[0]);
    close (p[1]);
    execvp (com2[0], com2); /* com2: grep */
    fatal ("2nd execvp call in join");
  }
}

 

 

#include <stdio.h>

main()
{
  char *one[4] = {"ls", "-l", "/usr/lib", NULL};
  char *two[3] = {"grep", "∧d", NULL};
  int ret;

  ret = join (one, two);
  printf ("join returned %d\n", ret);
  exit (0);
}

 

one이라는 거는 네개 element를 가진 포인터인데 ls -l path null 이렇게 되어있음 목록을 보는 명령어
two는 grep 하고 컨트롤d하는거는 grep은 패턴을 찾는거임 이런 글자가 들어가있는 패턴이 있는지 찾는 거임
이 명령을 array로 만들어서 join에 각각 넣어줌 
$ ls -l /usr/lib | grep ^d 이렇게 하나의 문자열로 들어옴 그럼 하나의 쉘에서 하나하나 파싱해서 one two만듦
이 작업을 쉘에서해줬는데 그 과정이 생략되어있음 이미됐다고 보고 중간에 파이프가 있는걸보고 join을 한거임

 

 join으로 들어오기전에 이미 파싱이 된 결과가 저장되어있음. 
그래서 cmd1이 각각 토큰별로 나누어져서 들어가져있음 그게 이제 어레이로 되어있음
그래서 join 하는 프로그램이 있고 fork 해서 child 만들고 또 fork 해서 child 만듦 


com1이 child 가 되고 그거에 대한 표준 출력이 pipe로 들어가고 gp가 shell 임 p 는 com2
parent의 표준 입력으로 들어오게 파이프를 연결해놓은 거임 
fork 해서 child 만들면 이 p를 만드는거임 com2 그래서 실패한 경우 -1 0이면 break 해서 if 문으로 감
이 첫번째 switch 문은 p 에서 시작함 wait는 gp 에서 실행하는거임 p 가 pip를 만들고 fork 함
이때만든 child 는 c임 0이면 이 부분은 c에서 실행함 default는 p가 실행함 


com1은 c는 p[1]을 사용함 dup2를 씀 그래서 p1을 standard output에다가 copy해줌 그러면 child 의 1이 더이상
표준출력이 아님. 이게 p1으로 바뀌는 거임. write(1이라고하면 스크린으로 안가고 파이프로 감
여기서 p0안쓰니까 close해줌 왜 p1을 클로즈하는거지? p1을 1로 copy해서 이미 1이 p1을 가리킴


여기 com1을 넣어서 자기 스스로를 변신시킴 

com1을 변신시키면 독립된 프로그램임 그래서 디스크립터 3,4가 열리면 안됨. 

그래서 close 시킨거임. p1이 필요한데 이건 표준츌력에 1 번에 copy해둔거임
com1을 child 가 실행해서 결과를 pipe에 둠 

parent의 com2를 보면 com1에서 넘어온 출력을 파이프로 부터 입력받음


표준입력으로 copy 해두면됨 그럼 pipe 에서 입력됨 read할 때 dup2 해서 함

com2로 변신함 3하고 4는 더이상 쓸모가없다고 close함

새로운 프로그램인데 자기는 3하고 4를 오픈한적이없으니 오픈하면안돼서 close함


Advanced IPC facility

advanced ipc는 posix 표준에 들어가있는거임 프로세스간에 정보교환에 이용되는 매커니즘 제공
메시지 큐, 세마포어, 쉐어드 메모리가 있음

 

메세지 큐라는 거는 파이프를 좀 더 advanced 하게한 거


shared memory는 프로세스간 변수를 공유할수있게 한거임 두개의 프로세스가 메모리를 공유할 수 없음

address space가 다름 그래서 메모리를 공유할수없음 근데 공유할수있게해서 변수를 공유할수있게 함


세마포어는 변수를 공유하거나 커뮤니케이션할때 신크로나이제이션 해줄 필요성이 절실히 요구됨
synchronization은 프로세스간에 실행의 순서를 제어해주는 그런 메커니즘임 그걸 세마포어로 해주는 것임


거기에 사용되는 시스템콜들이 메시지 큐에는 네개 세마포어는 세개 쉐어드메모리는 네개 이렇게 준비됨

 

mechanism

POSIX function

meaning

message queues

msgctl

control

msqget

create or access

msqrcv

receive message

msqsnd

send message

semaphores

semctl

control

semget

create or access

semop

execute operation (wait or post)

shared memory

shmctl

control

shmget

create and initialize or access

shmat

attach memory to process

shmdt

detach memory from process

Permission structure

struct ipc_perm {
	uid_t uid;
    	gid_t gid;
    	uid_t cuid;
    	gid_t cgid;
    	mode_t mode;
};

inode 에도 그 struct stat에 제일 첫번째 항목으로 permission이 있었음 st_mode
마찬가지로 세가지 메시지큐, 세마포어, 쉐어드메모리에는 마찬가지로 데이터 스트럭처가 있음 
struct msqid_ds, struct semid_ds, struct shmid_ds 이렇게 stat에 해당하는 것이 각각있었음


stat에 있듯이 이 데이터 스트럭쳐에도 맨 처음에 permission을 가리키는 멤버가 있음 그 멤버가 바로 ipc_perm 임
st_mode는 변수하나로 되어있었는데 여기서는 struct 구조로 되어있음


첫번째 항목으로 ipc perm이 다 들어있었음. 여기서 첫번째 항목으로 ipc perm 이 다 들어있음


맨 마지막 다섯번째에 mode_t mode에 permission이 들어감 여기에 read write만 있고 x는 의미 없음
owner의 euid, egid,
owner와 creator의 차이 : 만든사람이 creater이고 만든 프로세스에도 ruid, euid가 있는데 그 중 euid
ipc 오브젝트를 만들었다면 이것의 creater uid는 그 프로세스의 euid 임  gid 도 마찬가지


만든사람은 있더라도 ipc의 owner를 다른사람으로 바꿀 수 있음
그걸 남한테 줄때 owner가 바뀌게 됨 owner를 바꿔도 creator는 변화가 없음


ipc를 엑세스 할수있는 권한은 ruid, euid가 있으면 이 프로세스의 euid가 이 mode하고 부합해야됨
umask 만들때 mask 자동으로 안됨

우리가 owner 의 uid gid 그리고 mode를 바꿀수있음 msg ctl, semctl, shmctl
아무나 못바꾸고 creater나 super user는 되고, 크리에이터만 바꿀수있음 

 

Identifiers and Keys

파일 디스크립터에 해당하는게 identifier고 파일네임에 해당하는게 key임 
파일네임은 open 하고 파일네임을 쓰는데, 마찬가지로 open에 해당하는게 get이었음


msgget semget shmget여기 안에 key가 들어감 shmget(key) 그럼 return 값이 id임 open은 fd가 나왔음
fcntl stat read write 에서 fd를 쓴거처럼 msgqueue에는 send receive가 있는데, 거기엔 id를 씀


sys/type.h 보면 key_t 있음 long integer로 되어있음 typedef key_t long 
key는 ipc의 external name 이라면
identifier는 internal name임 얘도 숫자임 nonnegative 임


get에 key가 들어가서 return 되어 얻을 수 있음 그다음부터는 파일디스크립터처럼 identifier 써서 
근데 파일디스크립터랑 조금 다른 면이 있음 어떻게 다르냐면 파일디스크립터와는 달리 ipc facility identifier는 unique
p1 p2 프로세스가 있다면, 이 안에서 파일디스크립터는 012가 있고 p1에도 있고 p2에도 있음
근데 각각에 있는 0번이 모두 같음 근데 실제로 같은 파일을 가리키고 있지 않음
0번은 키보드니까 같다고 치더라도 3,4 번은 다름 근데 이 identifier는 시스템내에서 unique함
identifier를 써서 103이라고 하면 p1이랑 p2에서 말하는게 똑같음 

 

The ftok(2) system call

#include <sys/ipc.h>
key_t ftok(const char *path, int id);
// returns : key if ok, (key_t)-1 on error

파일네임은 unique하지 않음 근데 absolute pathname은 unique함 

파일네임은 absolute로 표현하면 unique하다고 함
key는 자칫잘못하면 unique하지 않게 할 수 있음.

 

프로세스1에서 프로세스2가 전혀다른 사람이 만든 프로세스 두갠데
여기서 key를 10703이라고 지딴엔 유니크하다고 썻다고 하면 우연하게도 다른사람이 다른프로세스에서 10703 
이렇게 쓰면 서로 자기는 다른 ipc를 염두해두고 했다하더라도 번호가 같으면 같아져버리는 꼴이 생김


그런 사고가 생길수있음 나만의 유니크한 key를 만들어야함
시스템콜에서 제공되는 리턴되는 키가 유니크하게 유니크한 키가 리턴되도록 해주는 시스템콜임


그래서 여기에 들어가는 argument가 중요함

pathname을 집어넣음 그리고 숫자를 집어넣은 ftok 얘기중임
나만의 return 값을 마들라면 여기 pathname에다가 내가 혼자쓰는 내 파일네임의 pathname을 쓰면 

유니크한 키가 나올 가능성이 높음 근데 다른사람도 내 파일의 pathname을 쓸 가능성도 있음 id 숫자 집어넣음


다른사람이 pathname하고 id하고 같을 가능성을 낮춤
id는 우연히 같은 번호가 나옴 key 번호가 같은게 나올 수 밖에 없음 

100퍼센츠 유니크하게 나온게 아니라 유니크하게 나올 확률을 높여줌 

100퍼센트 유니크하게 하는 방법은 뒤에 또있음
100퍼센트 유니크하지 않은 번호는 아님. 확률이 99.99% 유니크할 확률이 있는 키값을 리턴해줌


 

IPC get operations

#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>

int msgget(key_t key, int permflags);
int semget(key_t key, int nsems, int permflags); 
int shmget(key_t key, size_t size, int permflags); 

// returns : identifier if ok, -1 on error

key가 정해지면 file name에 해당하는게 정해져있으니까 ipc를 get해서 identifier를 얻어야함
msg큐는 sys/msg.h 가 있고 sem은 뭐 암튼 이렇게 헤더 있음 msgget해서 리턴되는게 identifier임
ipc를 만들때 permission을 주는 거임 


sem 이랑 shm 도 permission있는데 permflag 밑에 두개 있음 두번째 argument 더 있음 
sem 이 여러개 만들어짐 그래서 id가 가르켜주는 거 몇 개가 들어있는지가 nsems임 
size는 그 int x int y 의 크기임 key 값을 주는 방법은 이렇게 세가지가 있는 거임

key 값을 자기가 key=100이렇게 할당하는 방법이 두번째 방법임 이건 위험함 유니크 안될거같으니까
ftok를 써서 키값을 더 유니크하게 만드는 방법도 있음 100퍼는 아님 


100퍼 유니크하게 시스템에서 만들어주는 게있음 그게 커널에서 key 값을 return 해줌 
커널은 시스템 내에 어떤 ipc가 있는지 이미 다 알고 있음

그래서 그 중에서 사용되지 않은 번호가 없는 key를 리턴함
커널에서 키값을 리턴해주면 100퍼 유니크가 보장됨 그럼 ipc private이라는 상수를 사용함 


어떻게 쓰냐면 ipc private 값을 key 값 대신에 넣어주기만 하면됨 get함수 안에
flag 변수들에는 permission 들어가고 거기에다가 o_creat, o_excl 가 들어갈 수 있음

ipc_creat, ipc_excl 가들어감
o_creat o_excl 이랑 똑같은 역할을 함 o_creat 파일이 이미 있으면 그냥 open 하고 없으면 퍼미션 주고 만들어서 open


ipc_creat랑 ipc_excl 가 동시에 setting 되면 파일이 있으면 get을 안하고 error, 

파일이 없으면 permflag로 만들어서 get

 

퍼미션은 이렇게 user의 read write permission 이 있는데 other의 permission 머 이렇게 있음
msg q는 send receive 이렇게 하는데, send 할라면 write permission이 있어야함 
receive할라면 read permission이 있어야함 

 

IPC ctl operations

#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>

int msgctl(int msqid, int command, struct msqid_ds *buf ); 
int semctl(int semid, int semnum, int command,…/*union semun arg*/);
int shmctl(int shmid, int command, struct shmid_ds *buf); 
// returns : 0 if ok, -1 on error

 

세가지가 각각 있는데 ctl 가 하는 역할은 파일의 fcntl, stat 두가지 작업을 한번에 하는 시스템콜이라고 보면됨 

stat로 읽고 변경할 수 있었음 그리고 fcntl로 컨트롤할수있었는데 그런 것들을 함 
get에서 얻어진 id를 넣고, 명령을 집어 넣고, 특정 작업을 한다 이거임 
명령의 종류에는 밑에 표 세개가 있음 이건 기본 명령임 각 msgq sem shm에 대해서 추가적인 명령이 또 있음 
기본적인 명령들에 대해서 먼저 보도록 하겠음 

 


ipc_stat는 file name에서 stat라고 하는 것을 보면 유사성을 느낄수있음 ipc_stat은 각각 msgq라고 하면
struct msgid_ds라는 데이터스트럭처가 있었는데 여기에 msgq에대한 정보가 있음


sem의 struct semid_ds, shm 는 struct shmid_ds가 있음 

각각 명령을 이 ipc_stat 명령 넣으면 이 자료구조에 있는 내용을 각각 가져와서 그 내용을 볼 수 있게 한임

status information을 가져온거임 set은 값을 변경할수있는거임 

stat으로 가져온 정보중에서 일부를 변경할수있는거임
rm은 remove, id 가 갖고 있는거 remove하는 거임 시스템내에서 지워버리는거임 그 ipc를

 

정리하면 get이 있고 get에는 key가 있음 key를 넣는 세가지가 있음 user가 번호를 지정하고
key 자리에 상수를 넣는거임 이 key 값을 얻어서 직접 넣는거임 identifier를 얻음
shm 여기에 id 넣어서 사용

 

Accessing IPC resources from the shell

option

 

no option

all information , abbreviated format

-q

message queue

-m

shared memory

-s

semaphore

-a

all information, long format

-bcopt

 options specify which components of the available information to print

$ ipcs –s –a    /* all the available information about the semaphores  */

ipcs ipc status 라는 명령어임 cmd 에서 볼수있는거임 ipcrm

ipcs [-qms][-a | -bcopt]

 

ipcs는 현재 ipc 내용이 다 디스플레이 됨 
owner 가 누구고 퍼미션은 뭐고 암튼 어쩌고 저쩌고임
-s는 세마포어 -q는 msgq 
shm은 -m일거라함