Task 통신 및 동기화 : Message Queue, Semaphore Shared Memory

Slides:



Advertisements
Similar presentations
A 장형태.  병행프로세스 개요  상호배제 (Mutual Exclusion)  상호배제 ( 세마포어 )  모니터 (monitor)  프로세스간 2 가지 통신방법.
Advertisements

컴퓨터와 인터넷.
운영체제 Chapter 3 병형 프로세스 박요안.
운영체제 3주차 정리 박 남 규.
ㅎㅎ 구조체 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스 구조체 배열.
ㅎㅎ 구조체 C++ 프로그래밍 기초 : 객체지향의 시작 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스
2장. 프로그램의 기본 구성. 2장. 프로그램의 기본 구성 2-1"Hello, World!" 들여다 보기 /* Hello.c */ #include int main(void) { printf("Hello, World! \n"); return 0;
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 11장 프로세스간 통신 인공지능실험실 석사 2학기 이희재
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
Linux System Programming
제 9 장 구조체와 공용체.
공유 메모리[1] 공유 메모리 공유 메모리 생성: shmget(2) 같은 메모리 공간을 두 개 이상의 프로세스가 공유하는 것
Linux System Programming
조 병 규 Software Quality Lab. 한국교통대학교
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
Linux System Programming
제15장 파일 입출력 문자열을 출력하는 여러가지 방법 (15-2쪽) 문자열만 처리하는 입출력 함수
쉽게 풀어쓴 C언어 Express 제17장 동적메모리와 연결리스트 C Express Slide 1 (of 13)
UNIT 07 Memory Map 로봇 SW 교육원 조용수.
시스템 V IPC 기초[1] 시스템 V IPC 공통 요소 키 생성
10 시스템V의 프로세스간 통신.
Linux System Programming
10 시스템V의 프로세스간 통신.
양방향 파이프의 활용 양방향 통신 파이프는 기본적으로 단방향이므로 양방향 통신을 위해서는 파이프를 2개 생성한다.
제 3장. C보다 나은 C++ II.
12장 파이프.
07. 디바이스 드라이버의 초기화와 종료 김진홍
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
SqlParameter 클래스 선문 비트 18기 발표자 : 박성한.
컴퓨터 프로그래밍 기초 #02 : printf(), scanf()
파이프와 exec 시스템 호출 (ls | wc)
8 메모리 매핑.
Linux/UNIX Programming APUE (Interprocess Communication)
메시지 큐[5] – test1.c 메시지 제어: msgctl(2) #include <sys/msg.h>
13장 고급 입출력 함수 박사 4학기 최 성자.
TCP/IP Socket Programming…
03. 병행 프로세스 (Parallel Process)
11장. 1차원 배열.
사용자 함수 사용하기 함수 함수 정의 프로그램에서 특정한 기능을 수행하도록 만든 하나의 단위 작업
어서와 C언어는 처음이지 제14장.
UNIT 07 Memory Map 로봇 SW 교육원 조용수.
3장 상수 변수 기본 자료형 키워드와 식별자 상수와 변수 기본 자료형 형변환 자료형의 재정의.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express Slide 1 (of 22)
Analog to Digital Converter
19. 함수 포인터와 void 포인터.
3장. 변수와 연산자 교안 : 전자정보통신 홈페이지 / 커뮤니티/ 학술세미나
Lesson 2. 기본 데이터형.
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
DK-128 실습 내부 EEPROM 제어 아이티즌 기술연구소 김태성 연구원
School of Electronics and Information. Kyung Hee University.
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
2장. 변수와 타입.
컴퓨터 프로그래밍 기초 - 8th : 함수와 변수 / 배열 -
메모리 타입 분석을 통한 안전하고 효율적인 메모리 재사용
Signal & Inter-Process Communication
병행프로세스의개요 주세호.
Homework #12 (1/2) 프로그램을 작성하고, 프로그램과 실행 결과를 프린트하여 제출한다.
3. 모듈 (5장. 모듈).
TVM ver 최종보고서
발표자 : 이지연 Programming Systems Lab.
구조체(struct)와 공용체(union)
06. 디바이스의 등록과 해제 김진홍
1장 C 언어의 개요 C 언어의 역사와 기원 C 언어의 특징 프로그램 과정 C 프로그램 구조 C 프로그램 예제.
 6장. SQL 쿼리.
개정판 누구나 즐기는 C언어 콘서트 제13장 동적 메모리 출처: pixabay.
버스와 메모리 전송 버스 시스템 레지스터와 레지스터들 사이의 정보 전송을 위한 경로
7 생성자 함수.
6 객체.
병행 프로세스(Parallel Process)
2019 2학기 9장 배열과 포인터 1. 주소, 주소연산자(&) 2. 포인터, 역참조연산자(*) 3. 배열과 포인터.
Presentation transcript:

Task 통신 및 동기화 : Message Queue, Semaphore Shared Memory Chapter #12

강의 목차 IPC(Inter-Process Communication) 메시지 큐(Message Queue) 세마포어(Semaphore) 공유 메모리(Shared Memory) Unix System Programming Unix System Programming 2

IPC(Inter-Process Communication)

IPC(Inter-Process Communication) (1) 프로세스 통신 도구(IPC Facilites) : 비동기적으로 동작하는 프로세스간의 통신을 위하여 운영체제가 제공하는 도구 종류: Signal(신호) Pipe(파이프) Message Queue(메시지 큐) Semaphore(세마포어) Shared Memory(공유 메모리) Socket(소켓) 동일한 플랫폼 상에서 유사하게 구현되어 ICP 도구로 별도 분류하기도 함 Linux System Programming

IPC(Inter-Process Communication) (2) 프로세스 통신 도구 (IPC Facilites) : 세마포어(Semaphore) 프로세스 동기화와 자원 관리에 사용 프로세스간의 상호배제 문제 해결에 사용 공유 메모리(Shared Memory) 가장 빠른 프로세스 통신 도구 하나 이상의 프로세스에 부착하여 서로 공유하여 접근 가능 프로세스간의 공유 메모리 접근을 위해 동기화가 필요 메시지 큐(Message Queue) 프로세스들간에 이산적인 양의 데이터 송수신을 위해 사용 전송할 데이터를 메시지 형태로 생성하여 전달하고 메시지 수신을 통해 데이터 수신이 가능 인터넷 메일 서비스와 개념이 유사 Linux System Programming

IPC(Inter-Process Communication) (3) get ctl op 세마포어 semget semctl semop 공유 메모리 shmget shmctl shmop(shmat, shmdt) 메시지큐 msgget msgctl msgop(msgsnd, msgrcv) 기 능 IPC 도구의 생성 및 참조 기능 제공 소유자 및 접근 허가 변경 등의 기능 제공 IPC 도구의 연산(송수신 제어 등) 기능 제공 Linux System Programming

IPC(Inter-Process Communication) (4) get 시스템 호출 파일 열기 시스템 호출 open과 유사 새롭게 통신 도구를 생성하거나 이미 생성된 통신 도구에 대한 id를 반환하여 접근 가능하게 함 반환된 id는 파일 디스크립터와 비슷하게 동작 접근 허가 또한 파일 접근 허가와 비슷하게 규정 ctl 시스템 호출 통신 도구에 관한 상태 정보 읽기 몇몇 상태 정보(소유자, 그룹, 접근 허가 등)에 대한 변경 통신 도구의 제거 기능 op 시스템 호출 프로세스간의 데이터 전송을 실행 파일 시스템 호출 read/write와 유사 Shmat는 파일의 open과 유사하고, shmdt는 파일의 close와 유사 Linux System Programming

IPC(Inter-Process Communication) (5) IPC 도구 식별자 – IPC key 파일을 식별하기 위해 파일 이름을 사용하듯이 IPC 객체를 식별하기 위해 사용하는 정수형 숫자 프로세스들은 IPC key를 이용하여 IPC 자원을 공유 자료형: key_t (<sys/types.h>에 정의) IPC key 변환 시스템 호출 – ftok(file_to_key) IPC 도구의 공유를 편리하게 지원하기 위해 파일 경로명과 식별자를 IPC 도구에 부여하고, 이를 IPC key 값으로 변환하는 시스템 호출 char device Inode # of file key_t Linux System Programming

IPC(Inter-Process Communication) (6) IPC key 변환 시스템 호출 – ftok(file_to_key) Linux System Programming

IPC(Inter-Process Communication) (7) IPC 도구의 접근 허가 구조: struct ipc_perm 파일의 접근 허가와 유사한 기능을 지원 접근 모드에서 실행 모드는 무의미함 Linux System Programming

IPC(Inter-Process Communication) (8) IPC 도구 유형별로 생성된 IPC 객체를 관리하기 위해 운영체제가 유지하는 테이블 IPC 도구 유형별로 각각의 테이블을 유지 파일 테이블과 유사한 개념 Linux System Programming

IPC(Inter-Process Communication) (9) ipcs 명령 현재 사용중인 IPC 도구들의 상태(status)를 보여주는 명령 IPC 타입, 사용자 ID, key 값 그리고 접근 허가 등을 볼 수 있음 옵션을 사용하여 지정된 유형의 IPC 도구 상태 정보만을 접근 가능 -q : 메시지 큐, -m : 공유 메모리, -s : 세마포어 ipcrm 명령 IPC 객체를 제거하는 명령 IPC 도구 유형 및 key 값을 지정하는 원하는 IPC 객체를 제거 Linux System Programming

Message Queue

메시지 큐(Message Queue) (1) 프로세스간에 이산적인 데이터를 메시지 형태로 전송하는 통신 도구 파이프와 같이 FIFO 타입의 데이터 전송을 지원 메시지는 메시지와 바이트(byte)들의 모임으로 구성 메시지 유형은 정수값으로 여러가지 메시지 형태에 id를 부여하여 구별하기 위해 사용 바이트 모임은 전송하는 데이터를 의미하는 것으로 문자, 그림 또는 일련의 구조체 데이터 등을 전송하기 위햇 사용 관련 시스템 호출 함수 msgget() – 메시지 큐를 생성 msgsnd()/msgrcv() – 메시지 전송 및 수신 msgctl() – 메시지 큐 제어 Linux System Programming

메시지 큐(Message Queue) (2) 메시지 큐의 구조: 메시지 큐의 상태 구조체 : msgid_ds 메시지 큐 객체의 상태 정보를 저장하는 구조체 하나의 메시지 큐가 생성되면 하나의 msgid_ds 구조체가 생성 Linux System Programming

메시지 큐(Message Queue) (3) 메시지 큐의 동작: 전송 프로세스가 전송할 데이터를 메시지 형태로 만들어 메시지를 전송하면 전송된 메시지는 메시지 큐의 마지막에 연결된다 수신 프로세스는 메시지 큐에 존재하는 메시지를 선택적으로 수신할 수 있다. 수신 프로세스에서는 메시지를 수신할 때에 다음의 수신 정책 중에 하나를 지정하여야 한다. 메시지 큐에서 첫번째 메시지 메시지 큐에서 지정된 타입의 첫번째 메시지 메시지 큐에 있는 타입들의 범위들로 부터 첫번째 메시지 Linux System Programming

메시지 큐(Message Queue) (4) 메시지 큐의 생성: msgget() 메시지 큐 생성 시스템 호출 주어진 key를 갖는 메시지 큐가 존재하면 메시지 큐의 id를 반환하고, 그렇지 않으면 새롭게 메시지 큐를 생성하고 id를 반환 Linux System Programming

메시지 큐(Message Queue) (5) Linux System Programming

메시지 큐(Message Queue) (6) 메시지 큐의 생성: msgget() msgget() 시스템 호출의 flag 옵션 Linux System Programming

메시지 큐(Message Queue) (7) 메시지 큐 구조체: msqid_ds Linux System Programming

메시지 큐(Message Queue) (8) 메시지 큐 구조체 초기값 Linux System Programming

메시지 큐(Message Queue) (9) 메시지 큐의 제어: msgctl() 메시지 큐 제어 시스템 호출 메시지 큐의 상태를 질의하거나 상태 정보를 변경, 또는 메시지 큐를 제거하는 기능을 지원 Linux System Programming

메시지 큐(Message Queue) (10) 메시지 큐의 제어: msgctl() msgctl() 시스템 호출의 명령어 Linux System Programming

메시지 큐(Message Queue) (11) msgctl() 시스템 호출의 사용 예 메시지 큐 관련 자료 구조 선언 메시지 큐의 제거 메시지 큐의 소유자 변경 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msqid; struct msqid_ds ds; msgctl(msqid, IPC_RMID, (struct msqid_ds *)0); msgctl(msqid, IPC_STAT, &ds); ds.msg_perm.uid = 51; msgctl(msqid, IPC_SET, &ds); Linux System Programming

메시지 큐(Message Queue) (12) msgctl() 시스템 호출의 사용 예 메시지 큐의 접근 허가 변경 메시지 큐의 메시지 크기 변경 msgctl(msqid, IPC_STAT, &ds); ds.msg_perm.mode = 0660; msgctl(msqid, IPC_SET, &ds); msgctl(msqid, IPC_STAT, &ds); ds.msg_qbytes = 5000; msgctl(msqid, IPC_SET, &ds); Linux System Programming

메시지 큐(Message Queue) (13) 메시지 큐의 연산: msgsnd(), msgrcv() 메시지 구조체 : 메시지 유형은 전송되는 여러가지 유형의 메시지 형태를 분류하여 지정 메시지 텍스트는 전송하는 데이터를 저장 메시지 텍스트의 크기는 최소 0에서 최대 64 KB 이내이며, 묵시적으로 2048 바이트로 사용 #include <sys/msg.h> struct msgbuf { long mtype; /* 메시지 유형 */ char mtext[1]; /* 메지시 텍스트 */ } Linux System Programming

메시지 큐(Message Queue) (14) 메시지 송신 시스템 호출 : msgsnd() Linux System Programming

메시지 큐(Message Queue) (15) 메시지 송신 시스템 호출 : msgsnd() msgsnd 시스템 호출에 의한 메시지 큐 구조체 변경 Linux System Programming

메시지 큐(Message Queue) (16) 메시지 수신 시스템 호출 : msgrcv() Linux System Programming

메시지 큐(Message Queue) (17) 메시지 수신 시스템 호출 : msgrcv() msgrcv() 시스템 호출에서의 메시지 타입 지정 Linux System Programming

Linux System Programming 예제 프로그램 #1 (1) 하나의 메시지를 전송하고 수신하는 프로그램 // file name : ex9-1a.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct { long t; char a[60]; } x = {11L,"hello"}; main() { int mid; mid = msgget(11L,IPC_CREAT | 0666); msgsnd(mid,&x,strlen(x.a)+1,0); sleep(60); msgctl(mid,IPC_RMID,0); } Linux System Programming

Linux System Programming 예제 프로그램 #1 (2) // file name : ex9-1b.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct { long t; char a[60]; } x ; main() { int mid,rtn; mid = msgget(11L,0); rtn=msgrcv(mid,&x,60,0L,0); printf("rtn=%d type=%d text=%s\n",rtn,x.t,x.a); } Linux System Programming

Linux System Programming 예제 프로그램 #2 (1) 예제 프로그램 #1을 개선하여 여러 개의 메시지를 송수신하는 프로그램 // file name : ex9-2a.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SEND_SZ 30 #define DONE 99L main() { void perror(); key_t key; int mid; static struct { long mtype; char mtext[MAX_SEND_SZ]; } buf; Linux System Programming

Linux System Programming 예제 프로그램 #2 (2) static char *string[3] = { "hello", "how are you", "good-bye"}; int i,rtn; if((key= ftok(".",'a'))==-1) { perror("Can\'t form key"); exit(1); } mid = msgget(key,IPC_CREAT| 0660); if(mid == -1) { perror("Sender can not make msg queue!"); exit(2); Linux System Programming

Linux System Programming 예제 프로그램 #2 (3) buf.mtype = 1L; for(i=0;i<3;i++) { strcpy(buf.mtext,string[i]); if(msgsnd(mid,&buf,strlen(buf.mtext)+1,0)==-1) { perror("Sender can not msgsnd!"); exit(3); } rtn = msgrcv(mid,&buf,MAX_SEND_SZ,DONE,0); if(rtn == -1) { perror("Sender can not msgrcv"); exit(4); msgctl(mid,IPC_RMID,0); Linux System Programming

Linux System Programming 예제 프로그램 #2 (4) // file name : ex9-2b.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_RECV_SZ 60 #define FIFO 0L #define ZERO_LEN 0 #define DONE 99L static struct { long mtype; char mtext[MAX_RECV_SZ]; } buf; key_t key; int mid; int rtn; Linux System Programming

예제 프로그램 #2 (5) int main(int argv,char *argc[]) { void perror(); if((key= ftok(".",'a'))==-1) { perror("Can\'t form key"); exit(1); } mid = msgget(key,0); if(mid == -1) { perror("Receiver can not access msg queue!"); exit(2); while(1) { rtn = msgrcv(mid,&buf,MAX_RECV_SZ,FIFO,0); printf("rtn=%d buf.mtype=%ld buf.mtext=%s\n", rtn,buf.mtype,buf.mtext); if(!strcmp(buf.mtext,"good-bye")) break; buf.mtype = DONE; msgsnd(mid,&buf,ZERO_LEN,0); exit(0);

Linux System Programming 예제 프로그램 #3 (1) 메시지 송신 프로그램가 키보드 입력을 메시지로 만들어 여러 개의 수신 프로그램에 전달하는 프로그램 송신 프로그램은 fork()/exec() 시스템 호출을 통하여 수신 프로세스를 생성하고, 수신 프로세스는 수신된 메시지를 표준 출력으로 출력하도록 한다. // file name : ex9-3a.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SZ 80 #define NCHILD 3 Linux System Programming

Linux System Programming 예제 프로그램 #3 (2) #define WAIT_SOLE_USE(MSGQID) { \ int still_active = NCHILD; \ int i; \ long s_pid; \ s_pid = getpid(); \ while(still_active) { for(i=0;i<NCHILD;i++) \ if(msgrcv(MSGQID,&buf,MAX_SZ,s_pid,IPC_NOWAIT) != -1) \ if(!strncmp(buf.mtext,"DONE",4)) still_active--; \ sleep(2); \ } \ } int main(void) { void perror(); key_t ftok(); int msgqid; struct { long mtype; char mtext[MAX_SZ]; } buf; Linux System Programming

Linux System Programming 예제 프로그램 #3 (3) int msg_length; static char qid_evar[40]; static char *envp[2] = { qid_evar }; int this_fork, child; long r_pid[NCHILD]; char child_name[20]; int eof = 0; if((msgqid = msgget(IPC_PRIVATE,IPC_CREAT | 0660)) == -1) { perror("Sender can't make message queue!"); exit(1); } sprintf(qid_evar,"MQID=%d",msgqid); for(child=0;child<NCHILD;child++) { this_fork = fork(); if(this_fork == -1) { perror("fork failed"); exit(2); else if(this_fork == 0) { sprintf(child_name,"mwall_r%d",child); execle("ex9-3b",child_name,0,envp); perror("exec failed"); exit(3); Linux System Programming

Linux System Programming 예제 프로그램 #3 (4) else r_pid[child] = (long) this_fork; } setbuf(stdout,(char *) 0); while(1) { fprintf(stdout, "Enter message to be sent to all receivers:"); if(gets(buf.mtext) == (char *) 0) { fprintf(stdout,"\n"); eof++; strcpy(buf.mtext,"EOF"); msg_length = strlen(buf.mtext) +1; for(child=0;child<NCHILD;child++) { buf.mtype = r_pid[child]; if(msgsnd(msgqid,&buf,msg_length,0) == -1) { perror("Producer msgsnd error"); exit(4); if(eof) break; sleep(1); Linux System Programming

Linux System Programming 예제 프로그램 #3 (5) WAIT_SOLE_USE(msgqid); msgctl(msgqid,IPC_RMID,0); exit(0); } Linux System Programming

Linux System Programming 예제 프로그램 #3 (6) // file name : ex9-3b.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SZ 80 int main(int argc, char *argv[]) { void perror(); char *getenv(); long pid; char *valuep; int msgqid; struct { long mtype; char mtext[MAX_SZ]; } buf; Linux System Programming

Linux System Programming 예제 프로그램 #3 (7) pid = (long) getpid(); if((valuep = getenv("MQID")) == NULL) { fprintf(stderr,"%s:can't get env MQID\n",argv[0]); exit(1); } else sscanf(valuep,"%d",&msgqid); while(1) { msgrcv(msgqid,&buf,MAX_SZ,pid,MSG_NOERROR); printf("%s received '%s'\n",argv[0],buf.mtext); if(!strcmp(buf.mtext,"EOF")) break; buf.mtype = (long) getppid(); strcpy(buf.mtext,"DONE"); if(msgsnd(msgqid,&buf,strlen(buf.mtext),0) == -1) { fprintf(stderr,"%s:msgsnd error\n",argv[0]); exit(2); exit(0); Linux System Programming

Semaphore

Linux System Programming 세마포어(Semaphore) (1) 세마포어(Semaphore) 실행단위(프로세스 또는 쓰레드) 간의 동기화 도구 2개의 원자적 연산 P와 V가 정의되어 있는,정수값을 가지는 객체 s : 세마포어 P(s) : if ( s > 0 ) then s-- else 현재 프로세스는 대기한다; V(s) : if ( 1개 이상의 프로세스가 대기중 ) then   1개 프로세스만 진행한다 else s++; 일상 생활에서의 ‘신호등’과 같은 동작을 수행 철도 교통을 통제하기 위한 깃발신호로부터 유래 Linux System Programming

Linux System Programming 세마포어(Semaphore) (2) 세마포어(Semaphore) (계속) 세마포어 연산 P & V 는 원자적 연산(atomic operation) 하나의 프로세스가 P 또는 V 연산을 실행하는 도중에는 중지하지 않는다 어떤 프로세스가 P 또는 V 연산을 이용하여 세마포어에 접근하는 동안에는 다른 프로세스가 세마포어 값을 변경할 수 없다 세마포어의 활용 상호 배제(mutual exclusion) 문제 – 두 개 이상의 프로세스가 하나의 공유 자원을 접근할 때에 한 순간에 하나의 프로세스만 공유 자원을 접근할 수 있도록 보장함 실행 동기화 – 두 개 이상의 프로세스간에 실행 순서에 맞추어 실행됨을 보장함 Linux System Programming

Linux System Programming 세마포어(Semaphore) (3) 세마포어 종류 : 이진 세마포어(Binary Semaphore) 0 또는 1의 정수 값만 가지는 세마포어 P(s) 연산은 세마포어 s가 1일 때에 0으로 변경 V(s) 연산은 세마포어 s가 0일 때에 1로 변경 하나의 자원에 대한 공유 및 동기화를 지원 계수형 세마포어(Counting Semaphore) 범위에 제한이 없는 정수 값을 가지는 세마포어 일반적으로 언급하는 세마포어 다수의 공유 자원에 대해 여러 프로세스가 접근할 때에 상호 배제 및 동기화를 지원 Linux System Programming

Linux System Programming 세마포어(Semaphore) (4) 세마포어 이용 - 공유 자원에 대한 상호 배제(Mutual Exclusion) 여러 개의 프로세스가 하나의 자원을 공유하는 경우, 동시에 여러 프로세스가 자원을 접근하면 예상하지 못하는 문제가 발생함 예: 동시에 여러 프로그램이 프린터에 출력을 시도하는 경우 해결책 – 상호 배제 한 순간에 하나의 프로세스만 공유 자원을 접근함을 보장함 임계 영역(Critical Section) : 전체 프로그램 중에서 공유자원을 접근하는 프로그램 영역 한 순간에 임계 영역을 실행하는 프로세스는 하나만 존재하도록 보장함 세마포어를 이용하여 상호 배제를 구현 공유자원의 갯수에 따라 이진 세마포어 또는 계수형 세마포어를 사용 공유 자원에 대한 잠금과 풀기(lock & unlock) 기능을 지원 Linux System Programming

Linux System Programming 세마포어(Semaphore) (5) 세마포어 이용 - 공유 자원에 대한 상호 배제(Mutual Exclusion) 프로세스 P1 프로세스 P2 세마포어 s (초기값: 1) P(s) P(s) Critical Section 공유 자원 Critical Section V(s) V(s) Linux System Programming

Linux System Programming 세마포어(Semaphore) (6) 세마포어 이용 - 프로세스간의 실행 동기화(Synchronization) 하나의 프로그램이 여러 개의 프로세스로 이루어지는 경우, 프로세스간의 종속성에 의해 실행 순서가 정해지며, 반드시 실행 순서에 의해 동작하여함 예: 하나의 프로세스가 다른 프로세스가 제공하는 데이터를 받아 동작하는 경우 해결책 – 프로세스 실행 동기화 프로세서 P1가 T1 문장을 실행한 후에 프로세스 P2가 T2 문장을 실행하여야 하는 경우 프로세스 P2는 T2 문자을 실행하기 전에 프로세스 P1이 T1 문장을 실행하여는지를 검사 프로세스 P1이 T1 문장을 실행하였으면 바로 T2 문장을 실행 프로세스 P1이 T2 문장을 실행하지 않았으면 실행할 때까지 대기 세마포어를 이용하여 동기화를 지원함 대개의 경우 이진 세마포어를 사용 Linux System Programming

Linux System Programming 세마포어(Semaphore) (7) 세마포어 이용 - 프로세스간의 실행 동기화(Synchronization) 프로세스 P1 T1: ----- 프로세스 P2 T2: ----- 세마포어 s (초기값: 0) V(s) P(s) Linux System Programming

Linux System Programming 세마포어(Semaphore) (8) 세마포어의 생성: semget() Linux System Programming

Linux System Programming 세마포어(Semaphore) (9) 세마포어의 생성: semget() Linux System Programming

Linux System Programming 세마포어(Semaphore) (10) 세마포어의 생성: semget() semget() 시스템 호출의 동작 세마포어 구조체 초기화: Linux System Programming

Linux System Programming 세마포어(Semaphore) (11) 세마포어의 제어: semctl() 세마포어 제어 연산 세마포어의 집합 안에 개별적인 세마포어나 모든 세마포어에 대해 세마포어 값을 읽어오거나 새로운 값을 설정 세마포어 집합의 상태 정보을 읽어오거나 변경 세마포어에서 대기중인 프로세스의 수를 결정 마지막으로 세마포어를 연산한 프로세스를 결정 세마포어를 제거 semctl ()시스템 호출을 통해 상기의 세마포어 제어 연산을 실행 Linux System Programming

Linux System Programming 세마포어(Semaphore) (12) 세마포어의 제어: semctl() Linux System Programming

Linux System Programming 세마포어(Semaphore) (13) 세마포어의 제어: semctl() semctl() 시스템 호출의 명령어 및 반환값 Linux System Programming

Linux System Programming 세마포어(Semaphore) (14) 세마포어의 제어: semctl() 세마포어 생성 세마포어 집합에서 하나의 세마포어를 초기화 세마포어 집합에서 하나의 세마포어 값 읽기 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define ANY 0 int semid, rtn; struct semid_ds semds; ushort us[5], init_us[5] = {0, 6, 7, 1, 4}; … semid = semget(key, 5, IPC_CREAT|0666); semctl(semid, 2, SETVAL, 7); // GETCNT, GETZCNT, GETPID도 같은 형태로 사용 semctl(semid, 2, GETVAL, ANY); Linux System Programming

Linux System Programming 세마포어(Semaphore) (15) 세마포어의 제어: semctl() 세마포어 집합 내의 모든 세마포어의 값을 초기화 세마포어 집합 내의 모든 세마포어의 값 읽기 세마포어의 소유자 변경 세마포어 집합 제거 semctl(semid, ANY, SETALL, init_us); semctl(semid, ANY, GETALL, us); // 접근 허가 모드 변경에도 같은 형태로 사용 semctl(semid, ANY, IPC_STAT, &semds); semds.sem_perm.uid = 51; semctl(semid, ANY, IPC_SET, &ds); semctl(semid, ANY, IPC_RMID, ANY); Linux System Programming

Linux System Programming 세마포어(Semaphore) (16) 세마포어의 연산: semop() 세마포어의 값을 증가시키거나 감소시키는 연산을 수행 Linux System Programming

Linux System Programming 세마포어(Semaphore) (17) Linux System Programming

Linux System Programming 세마포어(Semaphore) (18) Linux System Programming

예제 프로그램 #4 (1) 세마포어를 이용하여 공유 자원에 대한 접근을 제어하는 프로그램 공유 자원은 표준 출력 // file name : ex10-1.c // #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> #define DUMMY 0 #define COUNT 4 int main(int argc, char *argv[]) { key_t ipckey; /* modified */ int semid, semget(),semctl(),semop(); int pid,getpid(); int creator,i; static struct sembuf lock = {0,-1,SEM_UNDO}; static struct sembuf unlock = {0, 1,SEM_UNDO}; setbuf(stdout,(char *) NULL);

Linux System Programming 예제 프로그램 #4 (2) ipckey = ftok(argv[0],'s'); if((semid = semget(ipckey,1,IPC_CREAT | IPC_EXCL | 0666)) != -1) { creator = 1; } else { if((semid = semget(ipckey,1,0)) == -1) { perror(argv[0]); exit(1); creator = 0; if(creator) { if(semctl(semid,0,SETVAL,1) == -1) { perror(argv[0]); exit(2); pid = getpid(); for(i=0;i<COUNT;i++){ if(semop(semid,&lock,1) == -1) { perror(argv[0]); exit(3); printf("\t[%d]locking\t",pid); sleep(1); printf("[%d] unlocking\n",pid); Linux System Programming

Linux System Programming 예제 프로그램 #4 (3) if (semop(semid,&unlock,1) == -1) { perror(argv[0]); exit(4); } if (creator) { sleep(5); if(semctl(semid,DUMMY,IPC_RMID,DUMMY) == -1) { perror(argv[0]); exit(5); Linux System Programming

예제 프로그램 #5 (1) 다음 그림과 세 개의 세마포어를 갖는 세마포어 집합을 이용하여 프린터 자원을 관리하는 프로그램 첫번째 세마포어는 두 개의 프린터 모두를 관리하는 계수형 세마포어 두번째 및 세번째 세마포어는 각각 프린터1과 프린터2를 관리하는 세마포어 프린터는 단말기 장치를 PRINTER1으로, 정규 파일을 PRINTER2로 환경 변수를 정의하여 시뮬레이션한다

예제 프로그램 #5 (2) #include <fcntl.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> #include "ex10-2.h" #define DUMMY 0 #define NUMPR 2 #define ACQUIRE -1 #define RELEASE 1 int main(int argc,char *argv[]) { char *getenv(), *printer[NUMPR], buf[BUFSIZ]; key_t ipckey; /* modified */ int semid, semget(), semctl(), semop(); ushort initial[NUMPR +1]; int i, prntnum, creator, getpid(); int n, fdin, fdout; struct sembuf operation[2]; char errmsg[30]; if((printer[1] = getenv("PRINTER1")) == (char *) NULL || (printer[2] = getenv("PRINTER2")) == (char *) NULL) { printf("missing printer assignment\n"); exit(1); }

예제 프로그램 #5 (3) if(strncmp(argv[0],"line",4) ==0) prntnum = 1; else if(strncmp(argv[0],"lase",4) ==0) prntnum =2; else prntnum = getpid() % NUMPR +1; ipckey = ftok(argv[0], 's'); if((semid = semget(ipckey,NUMPR +1,IPC_CREAT| IPC_EXCL| 0666)) != -1) { creator = 1; } else { if((semid = semget(ipckey, NUMPR +1, 0666)) == -1) { sprintf(errmsg, "%s - semget", argv[0]); perror(errmsg); exit(2); } if(creator) { /* initialize semaphore set */ initial[0] = NUMPR; for(i=1; i<= NUMPR; i++) initial[i] = 1; if(semctl(semid, DUMMY, SETALL, initial) == -1) { sprintf(errmsg,"%s -SETALL", argv[0]); perror(errmsg); exit(3); operation[1].sem_num = prntnum; operation[1].sem_op = ACQUIRE; operation[1].sem_flg = SEM_UNDO; operation[0].sem_num = 0; operation[0].sem_op = ACQUIRE; operation[0].sem_flg = SEM_UNDO;

예제 프로그램 #5 (4) if(semop(semid, operation, 2) == -1) { sprintf(errmsg,"%s - ACQUIRE", argv[0]); perror(errmsg); exit(4); } if((fdin = open(argv[1], O_RDONLY)) == -1) { sprintf(errmsg,"%s - %s", argv[0], argv[1]); perror(errmsg); exit(5); if((fdout = open(printer[prntnum], O_CREAT| O_WRONLY)) == -1) { sprintf(errmsg,"%s - %s", argv[0], printer[prntnum]); perror(errmsg); exit(6); while((n= read(fdin, buf, BUFSIZ)) > 0) write(fdout, buf, n); operation[1].sem_op = RELEASE; operation[0].sem_op = RELEASE; sprintf(errmsg,"%s - RELEASE", argv[0]); perror(errmsg); exit(7); exit(0);

예제 프로그램 #6 (1) 다음 그림과 같은 생산 라인을 시뮬레이션하는 프로그램 각 공정은 다중 프로세스를 생성하고 이들의 생산 순서와 소비 시간을 세마포어와 프로세스 수면(sleep)을 이용하여 시뮬레이션한다

예제 프로그램 #6 (2) // // header file name : ex10-3.h #define NWIDGETS 5 #define PARTA 0 #define PARTB 1 #define PARTC 2 #define SUB1 3 #define HOLDER 0

예제 프로그램 #6 (3) // // source file name : ex10-3a.c #include <signal.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "ex10-3.h" int semprodn; void endsim(); int main(int argc, char *argv[]) { int widget; int pgrp; char asc_prod_key[20]; static struct sembuf partc_sub1[2] = { { PARTC, -1, SEM_UNDO}, { SUB1, -1, SEM_UNDO} }; if((semprodn=semget(IPC_PRIVATE,4,IPC_CREAT | 0640)) == -1) printf("Can't get production line semaphore set\n"); exit(1); }

예제 프로그램 #6 (4) signal(SIGINT, endsim); sprintf(asc_prod_key,"%d", semprodn); if( fork() == 0) execl("ex10-3b","a", asc_prod_key, (char *)0); if( fork() == 0) execl("ex10-3b","b", asc_prod_key, (char *)0); if( fork() == 0) execl("ex10-3b","c", asc_prod_key, (char *)0); if( fork() == 0) execl("ex10-3c","ex10-3c", asc_prod_key, (char *)0); for(widget=1; widget < NWIDGETS; widget++) { semop(semprodn, partc_sub1, 2); printf("%s: ready to make widget #%d\n", argv[0], widget); } endsim(); void endsim() { semctl(semprodn, 0,IPC_RMID, 0); signal(SIGTERM, SIG_IGN); kill(0, SIGTERM); exit(0);

예제 프로그램 #6 (5) // // source file name : ex10-3b.c #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "ex10-3.h" int main(int argc, char *argv[]) { int semprodn, index; int unit = 0; static struct sembuf parti = { HOLDER, 1, SEM_UNDO }; static int prodtimeabc[3] = {2,3,4}; semprodn = atoi( argv[1] ); index = argv[0][0]- 'a'; /* argv[0] == [abc] */ parti.sem_num = index; while(1) { semop(semprodn, &parti, 1); printf("%s: producing unit #%d\n", argv[0], ++unit); sleep(prodtimeabc[index]); }

예제 프로그램 #6 (6) // // source file name : ex10-3c.c #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "ex10-3.h" int main(int argc, char *argv[]) { int semprodn; int unit = 0; static struct sembuf part_ab[2] = { {PARTA, -1, SEM_UNDO }, {PARTB, -1, SEM_UNDO } }; static struct sembuf sub1 = { SUB1, 1, SEM_UNDO }; semprodn = atoi( argv[1] ); while(1) { semop(semprodn, part_ab, 2); semop(semprodn, &sub1, 1); printf("%s: producing sub-assembly #%d\n", argv[0], ++unit); }

Shared Memory

공유메모리(Shared Memory) (1) 두 개이상의 프로세스가 실제 메모리의 일부를 공유하여 통신할 수 있는 IPC 도구 통신하려는 프로세스는 우선 공유 메모리를 할당받는다 프로세스는 할당된 공유 메모리를 자신의 가상주소공간 일부에 붙여(attach) 메모리에 데이터를 읽고 쓰는 것가 동일한 방법으로 필요한 데이터를 읽거나 전송하려는 데이터를 기록하여 상호 통신한다 프로세스간의 통신이 종료되면 공유 메모리를 가상주소공간에서 떼어내고(detach) 공유 메모리를 해제한다 IPC 도구 중에서 가장 효율적 시스템 간의 이식성이 낮음 프로세스간의 메모리 공유를 위해 별도의 하드웨어 지원이 필요 공유 메모리를 사용한 프로그램을 하드웨어 지원이 없는 시스템에서는 사용불가 Linux System Programming

공유메모리(Shared Memory) (2) 공유 메모리 시스템 호출 : shmget – 공유 메모리를 새롭게 할당하거나 할당된 공유 메모리의 핸들을 반환한다 shmctl – 공유 메모리와 관련된 상태 변수값을 변경하거나 공유 메모리를 제거한다 shmat – 공유 메모리를 프로세스의 가상주소공간에 논리적으로 부착(attach)한다 shmdt – 프로세스의 가상주소공간으로부터 공유 메모리를 분리한다 Linux System Programming

공유메모리(Shared Memory) (3) 공유 메모리 시스템 호출 : 공유메모리 shmget() 프로세스 P1 프로세스 P2 가상주소: 10000 shmat() 가상주소: 20000 shmat() shmdt() shmdt() shmctl() Linux System Programming

공유메모리(Shared Memory) (4) 공유 메모리의 생성: shmget() Linux System Programming

공유메모리(Shared Memory) (5) 공유 메모리의 생성: shmget() 공유 메모리 구조체 Linux System Programming

공유메모리(Shared Memory) (6) 공유 메모리의 생성: shmget() 공유 메모리 구조체의 초기화 Linux System Programming

공유메모리(Shared Memory) (7) 공유 메모리의 제어: shmctl() Linux System Programming

공유메모리(Shared Memory) (8) 공유 메모리의 제어: shmctl() shmctl() 시스템 호출의 명령어 Linux System Programming

공유메모리(Shared Memory) (9) 공유 메모리의 연산: shmat() / shmdt() Linux System Programming

예제 프로그램 #7 (1) 학원 강좌 예약 시스템 프로그램 부모 프로세스는 강좌 예약 정보를 갖는 공유 메모리을 할당하고, 공유 메모리에 대한 상호배제를 위한 세마포어를 생성한다 자식 프로세스을 생성하여 강좌 예약을 수행하는데, 자식 프로세스는 주기적으로 강좌 예약을 수행하도록 시뮬레이션하며, 더 이상 예약할 좌석(seat)가 없으면 종료한다 부모 프로세스는 모든 자식 프로세스가 종료할 때까지 기다렸다가 세마포어와 공유 메모리를 제거하고 종료한다 // // file name: ex11-1.h struct CLASS { char class_number[6]; char date[6]; char title[50]; int seats_left; } typedef struct CLASS class_t;

Linux System Programming 예제 프로그램 #7 (2) // file name: ex11-1a.c // #include <stdio.h> #include <memory.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include "ex11-1.h" class_t class = { "1001", "120186", "C Language for Programmers", 15 }; #define NCHILD 3 int child[NCHILD]; char *shm_ptr, *shmat(); int semid, shmid; char ascsemid[10], ascshmid[10]; char pname[14]; void rpterror(); int main(int argc, char *argv[]) { int i; Linux System Programming

예제 프로그램 #7 (3) strcpy(pname, argv[0]); shm_init(); sem_init(); for(i=0; i < NCHILD; i++) { child[i] = fork(); switch(child[i]) { case -1: rpterror("fork-failure"); exit(1); case 0: sprintf(pname,"ex11-1b%d",i+1); execl("ex11-1b", pname, ascshmid, ascsemid, (char *) 0); perror("execl faild"); exit(2); } wait_and_wrap_up(); shm_init() { shmid=shmget(IPC_PRIVATE, sizeof(class), 0600|IPC_CREAT); if(shmid == -1) { perror("shmget failed"); exit(3); shm_ptr = shmat(shmid, (char *) 0, 0); if(shm_ptr == (char *) -1) { perror("shmat failed"); exit(4); memcpy(shm_ptr,(char *) &class, sizeof(class)); sprintf(ascshmid,"%d", shmid);

예제 프로그램 #7 (4) sem_init() { if((semid=semget(IPC_PRIVATE, 1, 0600| IPC_CREAT)) == -1) { perror("semget failed"); exit(5); } if((semctl(semid, 0, SETVAL,1)) == -1) { printf("parent: semctl, SETVAL failed\n"); exit(6); sprintf(ascsemid,"%d",semid); wait_and_wrap_up() { int wait_rtn, w, ch_active = NCHILD; while(ch_active > 0) { wait_rtn = wait((int *) 0); for(w=0; w < NCHILD; w++) if(child[w] == wait_rtn) { ch_active--; break; printf("Parent removing shm and sem\n"); shmdt(shm_ptr); shmctl(shmid, IPC_RMID); semctl(semid, 0, IPC_RMID, 0); exit(0);

예제 프로그램 #7 (5) void rpterror(char *string) { char errline[50]; sprintf(errline,"%s %s",string, pname); perror(errline); }

예제 프로그램 #7 (6) // file name: ex11-1b.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include "ex11-1.h" class_t *class_ptr; char *memptr, *shmat(), *pname; int semid, shmid, ret; struct sembuf lock = { 0, -1, 0}; struct sembuf unlock = { 0, 1, 0}; void rpterror(); int main(int argc, char *argv[]) { if(argc < 3) { fprintf(stderr, "Usage: %s shmid semid\n", argv[0]); exit(1); } pname = argv[0]; sscanf(argv[1],"%d", &shmid); memptr = shmat(shmid, (char *) 0, 0);

예제 프로그램 #7 (7) if(memptr == (char *) -1) { rpterror("shmat failed"); exit(2); } class_ptr = (class_t *) memptr; sscanf(argv[2], "%d", &semid); sell_seats(); ret = shmdt(memptr); exit(0); sell_seats() { int all_out = 0; srand((unsigned) getpid()); while(! all_out) { /* loop to sell all seats */ if(semop(semid, &lock, 1) == -1) { rpterror("semop lock failed"); exit(4); if(class_ptr -> seats_left > 0) { class_ptr -> seats_left--; printf("%s SOLD SEAT -- %2d left\n", pname, class_ptr->seats_left);

예제 프로그램 #7 (8) else { all_out++; printf("%s sees no seats left\n", pname); } ret = semop(semid, &unlock, 1); if(ret ==-1) { rpterror("semop unlock failed"); exit(4); sleep((unsigned) rand() %10 +1); void rpterror(string) char *string; { char errline[50]; sprintf(errline,"%s %s",string, pname); perror(errline);

예제 프로그램 #8 (1) 세마포어와 공유 메모리를 이용하여 버퍼의 자료를 생산하고 소비하는 생산자/소비자(producer/consumer) 프로그램 생산자는 공유 메모리를 할당하여 버퍼를 설정한다 생산자와 소비자 사이에 버퍼 접근을 위한 동기화를 위해 2 개의 세마포어를 생성하여 사용한다 버퍼 쓰기 동기화(consumed 동기화) - 생산자는 소비자가 버퍼의 자료를 읽고 간 후에 새로운 자료를 버퍼에 쓴다 버퍼 읽기 동기화(produced 동기화) - 소비자는 생산자가 버퍼에 새로운 자료를 쓴 후에 자료를 읽어간다

예제 프로그램 #8 (2) // file name: ex11-2a.c // /* producer program: producer program sets up a buffer to be read by a consumer. semaphore are used to ensure taht producer dosen't overwrite an unread buffer and consumer dosen't read the same data more than once. */ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #define MSG_SIZE 30 #define MAX 5 main() { char *getenv(); key_t ftok(); char *shmat(); key_t key; void perror(), exit();

예제 프로그램 #8 (3) /* two semaphores in a set index 0 - incremented when producer has reset buffer - tested and decremented by consumer to check if buffer has been reset index 1 - incremented when consumer has read buffer - tested and decremented by producer to check if consumer is done. */ static struct sembuf wait_consumed = { 1, -1, 0}; static struct sembuf signal_produced = { 0, 1, 0}; int semid, shmid; char *message; int i; if((key = ftok(getenv("HOME"), 'u')) == (key_t) -1) { fprintf(stderr,"ftok key formation error\n"); exit(1); } semid = semget(key, 2, IPC_CREAT | 0660); if(semid == -1) { perror("producer semget():"); exit(2);

예제 프로그램 #8 (4) shmid = shmget(key, MSG_SIZE, IPC_CREAT | 0660); if(semid == -1) { perror("producer shmget():"); exit(3); } message = shmat(shmid, (char *) 0, 0); for(i=1; i < MAX; i++) { /* producer has to go first */ if(i>1) semop(semid, &wait_consumed, 1); sprintf(message, "message %d", i); semop(semid, &signal_produced, 1); shmdt(message); sleep(5); /* allow consumer to digest last message */ /* alternatively a DELIMITER string could be placed in shared memory when seen by the consumer, it would exit. the producer would do shmctl (..., IPC_STAT, ....) and when shm_attach == 1, it would remove the two IPC facilities */ shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0); shmctl(shmid, 0, IPC_RMID);

예제 프로그램 #8 (5) // file name: ex11-2b.c // /* consumer program: producer program sets up a buffer to be read by a consumer. semaphore are used to ensure taht producer dosen't overwrite an unread buffer and consumer dosen't read the same data more than once. */ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #define MSG_SIZE 30 int main(int argc, char *argv[]) { /* two semaphores in a set index 0 - incremented when producer has reset buffer - tested and decremented by consumer to check if buffer has been reset index 1 - incremented when consumer has read buffer - tested and decremented by producer to check if consumer is done.

예제 프로그램 #8 (6) key_t key; static struct sembuf wait_produced = { 0, -1, 0}; static struct sembuf signal_consumed = { 1, 1, 0}; int semid, shmid; char *message; int rtn; if((key = ftok(getenv("HOME"), 'u')) == (key_t) -1) { fprintf(stderr,"ftok key formation error\n"); exit(1); } /* either producer or consumer might be the creator but producer will be the remover of IPC resources. producer and consumer's effective uid must be the same. */ semid = semget(key, 2, IPC_CREAT | 0660); if(semid == -1) { perror("producer semget():"); exit(2);

예제 프로그램 #8 (7) shmid = shmget(key, MSG_SIZE, IPC_CREAT | 0660); if(semid == -1) { perror("producer shmget():"); exit(3); } message = shmat(shmid, (char *) 0, SHM_RDONLY); while(1) { rtn = semop(semid, &wait_produced, 1); /* when producer is done semid will be IPC_RMID forcing break */ if(rtn == -1) { perror("consumer - semop on wait_consumed"); break; printf("%s recevied: %s\n", argv[0], message); semop(semid, &signal_consumed, 1); shmdt(message);