# 12주차 1206 강의 요약
IPC: 프로세스들 사이에 서로 데이터를 주고 받는 행위 또는 그에 대한 방법이나 경로
IPC(Inter-Process Communication) 두 가지 방법
1. message queue
2. shared memory
### shminit.c
// shared memory를 하나 만들어서 초기화시키는 프로그램
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
int main(){
key_t key;
int shmid;
int *shmaddr;
key=100; // 두 프로세스 간의 고유한 key를 공유해야 한다
shmid=shmget(key,sizeof(int), IPC_CREAT | 0666); // 100이라는 key로 만들어진 shared memory에 쓸거야. 없으면 만든다
shmaddr = shmat(shmid, 0, 0); // attach
//printf("shmaddr = %p \n", shmaddr);
*shmaddr = 0; // 공유 메모리에 숫자 0을 저장
shmdt(shmaddr); // 다 쓰면 detach
}
### bash shell
gcc shminit.c -o shminit
./shminit
ipcs -m : shared memory의 정보를 보여줌
### shmsum.c
// shminit.c을 실행 후 shmsum.c를 실행하면 공유 메모리이므로 위에서 저장된 값에 접근 가능
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
int main(){
key_t key;
int shmid;
int *shmaddr;
int i, j;
key=100;
shmid=shmget(key,sizeof(int), IPC_CREAT | 0666); //공유 메모리에 값을 씀
shmaddr = shmat(shmid, 0, 0);
for (i=0; i<10; i++){
for(j=0; j<10000000; j++){
usleep(200000); // 0.2초
(*shmaddr)++; // shminit.c에서 저장된 공유메모리값에 접근하여 ++연산
}
}
printf("*shmaddr = %d \n", *shmaddr); // 100000000출력
shmdt(shmaddr);
}
### bash shell
gcc shmsum.c -o shmsum
./shmsum
ipcs -m
공유 메모리는 프로그램이 끝나도 지위지지 않음
shmsum을 실행할 때마다 shmaddr에 저장된 값이 +100000000 더해진 값이 출력
sleep: 단위 1sec
usleep: 단위 1micro sec (1/1000000sec)
shminit과 shmsum을 동시에 수행하면 원하는 결과값이 나오지 않는다 ..
왜? 공유 메모리를 두 개의 프로세스가 동시에 접근 ..
cpu가 하나있어도 오류가 발생한다 ..
문제 발생: cpu가 실행할 때 어셈블리 언어로 바꿔서 사용하게 됨
x=x+1이 cpu에서는 3가지 명령어로 쪼개서 실행됨
load $1, = x
add $2, $1, 1
store $2, = x
서로 다른 메모리를 동시에 읽고 쓰면 중간에 write가 끼게 되면 race condition이 발생할 수 도 있음(os과목 참고)
하드웨어는 하나인데 어떻게 하면 여러 개의 프로그램을 실행할 수 있을까? -> 공유된 자원을 한 번에 하나만 read, write하자.. -> 동기화 도구(semaphore, mutex lock)
## semaphore
동기화 도구: semaphore, mutex
semaphore란?
- 두 개 이상의 프로세스가 동시에 공유 메모리와 같은 공유 자원을 접근할 때 동기화를 걸어줌
- 공유된 자원의 데이터 혹은 임계영역(Critical Section) 등에 여러 Process 혹은 Thread가 접근하는 것을 막아줌(동기화 대상이 하나 이상)
semaphore는 int형 변수
wait(), signal(), init() 사용
- init()
딱 한번 초기화할 수 있음
- wait() // 감소
while(s<=0){block;} s—;
- post() (= signal()) // 증가
s++;
=> atomic하게 동작하는 것을 보장해준다 (한번에 하나만 실행하도록 보장해줌)
## POSIX Semaphore
### semainit.c
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <fcntl.h>
int main(){
sem_t *sem; //세마포어 데이터타입
int svalue;
int ival;
printf("Enter an integer: ");
scanf("%d: ", &ival); // 세마포어 초기값 받기
sem = sem_open("test", O_CREAT, 0666, ival); //새로운 세마포어 만들기 -> 세마포어 이름은 마음대로("test"), 세마포어 원하는 값(ival)으로 초기화
sem_getvalue(sem, &svalue); // 세마포어의 현재 값을 알 수 있음
printf("svalue = %d \n", svalue);
}
### bash shell
gcc semainit.c -o semainit -lpthread : 라이브러리를 포함해서 컴파일해야 함
./semainit
~/dev/shm 에 "sem.test"라는 세마포어가 파일형태로 생성됨
sem = sem_open("test", O_CREAT, 0666, ival);
test라는 세마포어가 이미 존재하면 새로 만들지 않고, 원래 있던 값을 쓰게 된다
test라는 세마포어가 없다면 초기값을 설정해서 만들 수 있다
rm /dev/shm/sem.test
이미 있는 세마포어를 지우고 다시 만들 수 있음
다시 만들때는 원하는 초기값으로 세마포어를 만들 수 있음
### s_wait.c
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <fcntl.h>
int main(){
sem_t *sem;
int svalue;
int ival;
sem = sem_open("testsem", O_CREAT, 0666, 1); //새로운 세마포어 만들기 -> 마지막 원하는 값으로 초기화
sem_wait(sem);
printf("wait is done \n");
}
### s_post.c
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <fcntl.h>
int main(){
sem_t *sem;
int svalue;
int ival;
sem = sem_open("testsem", O_CREAT, 0666, 1); //새로운 세마포어 만들기 -> 마지막 원하는 값으로 초기화
sem_post(sem);
printf("post is done \n");
}
### semwork.c
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include<unistd.h>
int main(){
sem_t *sem;
int work_t, i;
sem = sem_open("testsem", O_CREAT, 0666, 1); //새로운 세마포어 만들기 -> 1으로 초기화
srand(time(NULL)); // 난수 생성
for (i=0; i<10; i++){
printf("Trying to get a semaphore \n");
sem_wait(sem); //while(s<=0){block;} s--;
work_t = rand()%5 +1; // 1~5까지 난수 생성
printf("Working for %d sec \n", work_t);
sleep(work_t);
printf(" Done\n\n");
sem_post(sem); // s++;
sleep(1);
}
}
앞 뒤로 sem_wait(sem), sem_post(sem)으로 감싸주면, 여러 프로세스가 동시에 수행될 때 한 번에 하나만 수행되도록 보장해준다.
### bash shell
gcc semwork.c -o semwork -lpthread
./semwork
rm /dev/shm/sem.testsem
- 세마포어의 초기값을 0으로 설정하면? sem_wait => while(s<=0){block;} s—; 에 걸려서 모든 프로세스가 무한 block에 걸리게 된다
- 세마포어의 초기값을 2로 설정하면? 3개의 프로세스를 동시에 수행하면 2개의 프로세스가 동시에 수행될 수 있음
- 세마포어의 초기값을 100으로 설정하면? 동시에 100개의 프로세스를 동시에 수행할 수 있음
ipcs -a : 모든 IPC 자원을 조회
ipcs -q : 메시지 큐 자원을 조회
ipcs -m : 공유메모리 자원을 조회
ipcs -s : 세마포어 자원을 조회
ipcrm -q [ID] : 해당 메시지 큐 자원을 삭제
ipcrm -m [ID]: 해당 공유메모리 자원을 삭제
ipcrm -s [ID]: 해당 세마포어 자원을 삭제
2개의 세마포어, 1개의 공유변수
## 실습
(1) Shared Memory 이용한 메시지 전달하기 (동기화를 위해서 Semaphore 2개 사용 필요)
- program A
+ 키보드로 입력받은 문자열을 공유메모리에 write한다.
+ 프로그램 B가 공유 메모리에 새로운 문자열을 쓰기를 기다린다.
+ 그리고, 그 문자열을 출력한다.
+ 이 과정을 "end"를 입력할 때까지 반복한다.
- program B
+ program A가 새로운 문자열을 write하기를 기다린다.
+ 그 문자열을 출력하고, 새로운 문자열을 만든다. ("예: strcat을 사용해서 msg + "이름")
+ 새로 만든 문자열을 공유메모리에 write한다.
+ 이 과정을 program A가 "end"를 받을 때까지 반복한다.
(2) 제출물
- 두 개의 프로그램 소스 코드
- 실행화면 캡쳐한 이미지 파일
### A.c
#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <stdlib.h>
int main() {
char buf[100];
char buf2[100];
// A
sem_t *sem;
sem = sem_open("AAA", O_CREAT, 0666, 0);
int svalue;
sem_getvalue (sem, &svalue);
printf("program A svalue=%d \n", svalue); // 값 확인
// B
sem_t *sem2;
sem2 = sem_open("BBB", O_CREAT, 0666, 0);
sem_getvalue (sem2, &svalue);
printf("program B svalue=%d \n", svalue); // 값 확인
// 공유메모리
key_t key=100;
int shmid;
char *shmaddr;
shmid = shmget(key, sizeof(char)*100, IPC_CREAT | 0666);
shmaddr = shmat(shmid, NULL, 0);
while(1){
// program A
printf("This is Program A \n");
printf ("Enter a string to send in program A: ");
gets (buf);
//공유메모리에 쓰기
strcpy(shmaddr, buf);
sem_post(sem);
if (!strcmp(buf, "end")){exit(0);}
// program B
sem_wait(sem2);
sleep(2);
printf("This is Program B\n");
strcpy(buf, shmaddr);
printf("Program B string is [%s] \n", buf);
}
shmdt(shmaddr);
return 0;
}
### B.c
#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <stdlib.h>
int main() {
char buf[100];
char buf2[100];
// A
sem_t *sem;
sem = sem_open("AAA", O_CREAT, 0666, 0);
int svalue;
sem_getvalue (sem, &svalue);
printf("program A svalue=%d \n", svalue); // 값 확인
// B
sem_t *sem2;
sem2 = sem_open("BBB", O_CREAT, 0666, 0);
sem_getvalue (sem2, &svalue);
printf("program B svalue=%d \n", svalue); // 값 확인
// 공유메모리
key_t key=100;
int shmid;
char *shmaddr;
shmid = shmget(key, sizeof(char)*100, IPC_CREAT | 0666);
shmaddr = shmat(shmid, NULL, 0);
while(1){
// program A
sem_wait(sem);
printf("This is Program A \n");
//공유메모리에서 읽기
strcpy(buf, shmaddr);
printf("get from shared memory: [%s] \n", buf);
if (!strcmp(buf, "end")){exit(0);}
sleep(1);
strcat(buf, "bokyung");
strcpy(shmaddr, buf);
printf("Program B string is [%s] \n", buf);
sem_post(sem2);
}
shmdt(shmaddr);
return 0;
}
이번 시간 : semaphore
다음 시간: mutex lock
'Linux' 카테고리의 다른 글
[Linux] thread programming, mutex lock, semaphore in thread programming (0) | 2022.12.13 |
---|---|
[Linux] message queue, shared memory (0) | 2022.12.12 |
[Linux] fork, pipe, mkfifo (0) | 2022.12.11 |
[Linux] programming shell, execvp, fork (0) | 2022.12.09 |