240 likes | 539 Views
운영체제 개론 및 실습. 단국대학교 정보 컴퓨터학부 2007 년 4 월 최종무 choijm@dku.edu http://embedded.dankook.ac.kr/~choijm. kernel. kernel. struct msqid_ds. stack. stack. sending tasks. T. T. T. heap. heap. msg. msg. msg. data. data. text. shared memory. T. text. T. receiving tasks. IPC.
E N D
운영체제 개론 및 실습 단국대학교 정보 컴퓨터학부 2007년 4월 최종무 choijm@dku.edu http://embedded.dankook.ac.kr/~choijm
kernel kernel struct msqid_ds stack stack sending tasks T T T heap heap msg msg msg data data text shared memory T text T receiving tasks IPC • semaphore • memory에 접근하는 process들의 동기화 지원 • shared memory ? • process들이 memory를 공유하고 이를 통해 통신하는 기능을 지원 • message queue ? • process들 사이에 message를 주고 받는 기능을 지원
IPC • System V IPC 3가지 유형의 공통점 • IPC 식별자(identifier) 사용 • IPC 객체에 접근하기 위해서는 식별자 필요 • Key를 identifier 로 매핑 (ftok) • 통신을 하려는 프로세스는 키를 공유해야 함 • 커널에 ***id_ds라는 자료 구조 생성 (eg: msqid_ds) • IPC 관련 명령어 제공: ipcs, ipcrm, ..
IPC #include <sys/ipc.h> key_t ftok(const char *path, int id); • 파일의 경로명을 key로 변환 • 매개변수 • path : 경로명 • id : 임의의 정수 값
철학자들의 만찬 • Scenario • 각각의 철학자는 다른 철학자에게 말을 할 수 없다. • 철학자가 스파게티를 먹기 위해서는 양 옆의 포크를 동시에 들고 있어야 한다. • Problem • 교착 상태 • 에츠허트 데이크스트라의 해결책 • 각각의 철학자: p1,p2,p3,p4,p5 • 왼쪽 포크: f1,f2,f3,f4,f5 • p5를 제외한 네 명은 f n -> f n+1, p5는 f1->f5
semaphore 제어 매개변수 semid : semget호출로 얻은 식별자 semnum : semaphore set의 원소 cmd : 연산의 종류 Semaphore Set #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); • semaphore 생성 or 접근 • 매개변수 • key : 고유의 semaphore에 접근하기 위해 사용 • nsems : semaphore가 만들어 질 수 있는 크기(원소의 갯수) • semflg : 접근 권한 정의(생성자 1?, 소비자 0?) #include <sys/sem.h> int semctl(int semid, int semnum, int cmd, …);
Semaphore Set #include <sys/sem.h> int semop(int semid, struct sembuf *sops, size_t nsops); • 사용자 정의 semaphore 연산을 원자적으로 수행 • 매개변수 • sops : 원소 연산의 배열 • nsops : 배열내의 원소 연산의 개수
예제 1(chainsemset.c) 1/5 • chainsemset.c int initelement(int semid, int semnum, int semvalue); int r_semop(int semid, struct sembuf *sops, int nsops); int removesem(int semid); void setsembuf(struct sembuf *s, int num, int op, int flg); void printerror(char *msg, int error); pid_t r_wait(int *stat_loc); int initelement(int semid, int semnum, int semvalue){ union semun{ int val; #include <errno.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/sem.h> #include <sys/stat.h> #include <sys/wait.h> #define BUFSIZE 1024 #define PERM (S_IRUSR | S_IWUSR)
예제 1(chainsemset.c) 2/5 struct semid_ds *buf; unsigned short *array; }arg; arg.val = semvalue; return semctl(semid, semnum, SETVAL, arg); } int r_semop(int semid, struct sembuf *sops, int nsops){ while(semop(semid, sops, nsops) ==-1) if(errno != EINTR) return -1; return 0; } void setsembuf(struct sembuf *s, int num, int op, int flg){ s->sem_num = (short)num; s->sem_op = (short)op; s->sem_flg = (short)flg; return; } void printerror(char *msg, int error){ fprintf(stderr, "[%ld] %s : %s \n", (long)getpid(), msg, strerror(error)); } pid_t r_wait(int *stat_loc){ int retval;
예제 1(chainsemset.c) 3/5 int error; int i, j, n; int semid; struct sembuf semsignal[1]; struct sembuf semwait[1]; if( (argc!=3) || ((n=atoi(argv[1]))<=0) || ((delay = atoi(argv[2]))<0) ){ fprintf(stderr, "Usage : %s processes delay\n", argv[0]); return 1; } if((semid= semget(IPC_PRIVATE, 1, PERM)) == 1){ while(((retval = wait(stat_loc)) == -1) && (errno == EINTR)); return retval; } int removesem(int semid){ return semctl(semid, 0, IPC_RMID); } int main(int argc, char *argv[]){ char buffer[BUFSIZE]; char *c; pid_t childpid; int delay;
예제 1(chainsemset.c) 4/5 for(i = 1; i<n; i++) if(childpid = fork()) break; snprintf(buffer, BUFSIZE, "i:%d PID:%ld parent PID:%d child PID:%ld\n", i, (long)getpid(), (long)getppid(), (long)childpid); c=buffer; if(((error= r_semop(semid, semwait, 1)) == -1)&& (i>1)){ printerror("Child failed to lock semid", error); return 1; } perror("Failed to crate a private semaphore"); return 1; } setsembuf(semwait, 0, -1, 0); setsembuf(semsignal, 0, 1, 0); if(initelement(semid, 0, 1) == -1){ perror("Failed to initialize semaphore element to 1"); if(removesem(semid) == -1) perror("Failed to remove failed semaphore"); return 1; }
예제 1(chainsemset.c) 5/5 if((r_wait(NULL) == -1) && (errno != ECHILD)) printerror("Failed to wait", errno); if((i==1) && ((error = removesem(semid)) == -1)){ printerror("Failed to clean up", error); return 1; } return 0; } else if(!error){ while(*c != '\0'){ fputc(*c, stderr); c++; for(j=0; j<delay;j++); } if((error = r_semop(semid, semsignal, 1)) == -1) printerror("Failed to unlock semid", error); }
shard memory를 사용하기 위해 attach 매개변수 shmid : shmget호출로 얻은 식별자 shmaddr : 메모리가 attach될 주소 명시(보통 0) shmflg : read or write mode 지정 Shard Memory #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); • kernel에 shard memory 공간을 요청 • 매개변수 • key : 고유의 공유메모리에 접근하기 위해 사용(공유메모리 구분) • size : 공유메모리의 최소 크기 • shmflg : 접근 권한과, 생성 방식 정의 #include <sys/shm.h> void shmat(int shmid, const void *shmaddr, int shmflg)
Shard Memory #include < sys/shm.h> int shmdt(const void *shmaddr); • shard memory와 process를 detach • 매개변수 • shmaddr : 공유 메모리 세그먼트의 시작 주소 #include < sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf); • shard memory를 제어 하기 위해 사용 • 매개변수 • shmid : 식별자 • cmd : 제어 하고자 하는 내용 • IPC_RMID • IPC_SET • IPC_STAT • buf : cmd에 따라 다름
Shard Memory #include < sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf); • shard memory와 process를 detach • 매개변수 • shmid : 식별자 • cmd : • sval = 0? • sval = -3?
예제2(shm_srv.c)1/2 // Attach the segment. if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } // Put some things into the memory. s = shm; for (c = 'a'; c <= 'z'; c++) *s++ = c; *s = NULL; // We wait until the other process while (*shm != '*') sleep(1); exit(0); } #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #define SHM_MAX_SIZE 256 main() { char c; int shmid; key_t key; char *shm, *s; // Create the key. key = ftok(".",1234); // Create the segment. if ((shmid = shmget(key, SHM_MAX_SIZE, IPC_CREAT | 0666)) < 0) { perror("shmget"); exit(1); }
예제2(shm_cli.c)2/2 18 // Attach the segment. if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } // Read what the server put in the memory. for (s = shm; *s != NULL; s++) putchar(*s); putchar('\n'); // Change the first character of the segment to '*' *shm = '*'; exit(0); } #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #define SHM_MAX_SIZE 256 main(){ int shmid; key_t key; char *shm, *s; // Create the key. key = ftok(".",1234); // Locate the segment. if ((shmid = shmget(key, SHM_MAX_SIZE, 0666)) < 0) { perror("shmget"); exit(1); }
Message Queue IBM’s WebSphere MQ MSMQ(Microsoft Message Queuing)
msg Q에 msg를 삽입 매개변수 msgid : 식별자 msgq : Q에 삽입 하고자 하는 msg의 포인터 msgsz : msg의 크기 msgflg : 여러 조건에서 취할 행동을 명시 Message Queue #include <sys/msg.h> int msgget(key_t key, int msgflg); • 새로운 msg Q를 생성하거나 기존 msg Q 에 접근 • 매개변수 • key : 고유의 msg Q에 접근하기 위해 사용(msg Q 구분) • shmflg : 접근 권한과, 생성 방식 정의 #include <sys/msg.h> int msgsnd(int msqid, condt void *msgp, size_t msgsz, int msgflg);
msg Q를 해제하거나 권한을 변경 매개변수 shmctl의 매개변수와 비슷함 Message Queue #include <sys/msg.h> ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); • msg Q에 msg를 추출 • 매개변수 • msgq : Q에서 추출한 msg를 저장할 공간의 포인터 • msgtyp : 메시지의 선택을 위해 수신자에 의해 사용 #include <sys/msg.h> void msgctl(int msqid, int cmd, struct msqid_ds *buf);
Quiz2 1/3 22 지금까지 배운 Message Queue 함수들을 사용해서 하나의 프로그램에서 입력 받은 문자열을 Message Queue에 전송하고 또 다른 프로그램에서 그 문자열을 수신하여 출력하는 프로그램을 작성하시오.
Quiz2(msgq_send.c)2/3 23 헤더파일 <sys/types.h> <sys/ipc.h> <sys/msg.h> <stdio.h> <string.h> <stdlib.h> #define MSGMAX 256 typedef struct msgbuf { // Message structure. long mtype; char mtext[MSGMAX]; } message_buf; main() { int msqid; int msgflg = IPC_CREAT | 0666; key_t key; message_buf buf; size_t buf_length; char msg_str[MSGMAX]; // Create key. // Get the message queue id printf("\nmsgget: Calling msgget(%lx, %o)\n", key, msgflg); if (( message queue 에 접근 msgget() 사용) < 0) { perror("msgget"); exit(1); } else { printf("msgget: msgget succeeded: msqid = %d\n", msqid); } printf("Input your message : "); // fgets() 사용해서 문자열 입력받기 // Send message type is 1 buf.mtype = 1; // strcpy() 사용해서 buf.mtext 에 입력받은 문자열값 넣기 buf_length = strlen(buf.mtext) + 1 ; if(msgsnd() 사용해서 메시지 전송 마지막 인자는 IPC_NOWAIT < 0){ printf ("%d, %d, %s, %d\n", msqid, buf.mtype, buf.mtext, buf_length); perror("msgsnd"); exit(1); } else { printf("Sent message: %s\n", buf.mtext); } exit(0); }
Quiz2(msgq_send.c)2/3 24 헤더파일 <sys/types.h> <sys/ipc.h> <sys/msg.h> <stdio.h> <string.h> <stdlib.h> #define MSGMAX 256 // message_buf 란 이름으로 Message structure 선언. main() { int msqid; key_t key; message_buf buf; // Create key. // Get the msg queue id if ((message queue 에 접근 msgget() 사용 < 0) { perror("msgget"); exit(1); } // Receive an answer of message type 1. if (msgrcv(msqid, &buf, MSGMAX, 1, 0) < 0) { perror("msgrcv"); exit(1); } printf("Receive message: %s\n", buf.mtext); exit(0); }