슬라이드 1

Download Report

Transcript 슬라이드 1

Linux System
Programming
Lecture #11
– 공유메모리(Shared Memory)
공유메모리(Shared Memory) (1)

공유메모리 정의 :

두 개이상의 프로세스가 실제 메모리의 일부를 공유하여 통신할
수 있는 IPC 도구
통신하려는 프로세스는 우선 공유 메모리를 할당받는다
 프로세스는 할당된 공유 메모리를 자신의 가상주소공간 일부에 붙여
(attach) 메모리에 데이터를 읽고 쓰는 것가 동일한 방법으로 필요
한 데이터를 읽거나 전송하려는 데이터를 기록하여 상호 통신한다
 프로세스간의 통신이 종료되면 공유 메모리를 가상주소공간에서 떼
어내고(detach) 공유 메모리를 해제한다



IPC 도구 중에서 가장 효율적
시스템 간의 이식성이 낮음
프로세스간의 메모리 공유를 위해 별도의 하드웨어 지원이 필요
 공유 메모리를 사용한 프로그램을 하드웨어 지원이 없는 시스템에서
는 사용불가

Linux System Programming
2
공유메모리(Shared Memory) (2)

공유 메모리 시스템 호출 :




shmget – 공유 메모리를 새롭게 할당하거나 할당된 공유 메모리
의 핸들을 반환한다
shmctl – 공유 메모리와 관련된 상태 변수값을 변경하거나 공유
메모리를 제거한다
shmat – 공유 메모리를 프로세스의 가상주소공간에 논리적으로
부착(attach)한다
shmdt – 프로세스의 가상주소공간으로부터 공유 메모리를 분리한
다
Linux System Programming
3
공유메모리(Shared Memory) (3)

공유 메모리 시스템 호출 :
shmget()
프로세스 P1
프로세스 P2
공유메모리
shmat()
가상주소:
10000
shmdt()
shmat()
shmdt()
가상주소:
20000
shmctl()
Linux System Programming
4
공유메모리(Shared Memory) (4)

공유 메모리의 생성: shmget()
Linux System Programming
5
공유메모리(Shared Memory) (5)

공유 메모리의 생성: shmget()

공유 메모리 구조체
Linux System Programming
6
공유메모리(Shared Memory) (6)

공유 메모리의 생성: shmget()

공유 메모리 구조체의 초기화
Linux System Programming
7
공유메모리(Shared Memory) (7)

공유 메모리의 제어: shmctl()
Linux System Programming
8
공유메모리(Shared Memory) (8)

공유 메모리의 제어: shmctl()

shmctl 시스템 호출의 명령어
Linux System Programming
9
공유메모리(Shared Memory) (9)

공유 메모리의 연산: shmat()/shmdt()
Linux System Programming
10
예제 프로그램 (1)

예제 11-1




학원 강좌 예약 시스템 프로그램
부모 프로세스는 강좌 예약 정보를 갖는 공유 메모리을 할당하
고, 공유 메모리에 대한 상호배제를 위한 세마포어를 생성한다
자식 프로세스을 생성하여 강좌 예약을 수행하는데, 자식 프로
세스는 주기적으로 강좌 예약을 수행하도록 시뮬레이션하며,
더 이상 예약할 좌석(seat)가 없으면 종료한다
부모 프로세스는 모든 자식 프로세스가 종료할 때까지 기다렸
다가 세마포어와 공유 메모리를 제거하고 종료한다
Linux System Programming
11
예제 프로그램 (2)
//
// 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
12
예제 프로그램 (3)
// 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
int
char
char
void
*shm_ptr, *shmat();
semid, shmid;
ascsemid[10], ascshmid[10];
pname[14];
rpterror();
int main(int argc, char *argv[])
{
Linux System Programming
int i;
13
예제 프로그램 (4)
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));
Linux System Programming
sprintf(ascshmid,"%d", shmid);
}
14
예제 프로그램 (5)
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);
Linux System Programming
exit(0);
}
15
예제 프로그램 (6)
void rpterror(string)
char *string;
{
char errline[50];
sprintf(errline,"%s %s",string, pname);
perror(errline);
}
Linux System Programming
16
예제 프로그램 (7)
// 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
char
int
struct
struct
void
*class_ptr;
*memptr, *shmat(), *pname;
semid, shmid, ret;
sembuf lock = { 0, -1, 0};
sembuf unlock = { 0, 1, 0};
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);
Linux System Programming
17
memptr = shmat(shmid, (char *) 0, 0);
예제 프로그램 (8)
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,
Linux System Programming
18
class_ptr->seats_left);
}
예제 프로그램 (9)
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);
}
Linux System Programming
19
예제 프로그램 (10)

예제 11-2



세마포어와 공유 메모리를 이용하여 버퍼의 자료를 생산하고
소비하는 생산자/소비자(producer/consumer) 프로그램
생산자는 공유 메모리를 할당하여 버퍼를 설정한다
생산자와 소비자 사이에 버퍼 접근을 위한 동기화를 위해 2 개
의 세마포어를 생성하여 사용한다
버퍼 쓰기 동기화(consumed 동기화) - 생산자는 소비자가 버퍼의
자료를 읽고 간 후에 새로운 자료를 버퍼에 쓴다
 버퍼 읽기 동기화(produced 동기화) - 소비자는 생산자가 버퍼에
새로운 자료를 쓴 후에 자료를 읽어간다

Linux System Programming
20
예제 프로그램 (11)
// 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
#include
#include
#include
#include
<stdio.h>
<sys/types.h>
<sys/ipc.h>
<sys/sem.h>
<sys/shm.h>
#define MSG_SIZE 30
#define MAX 5
main()
{
char *getenv();
key_t ftok();
char *shmat();
key_t key;
Linux System Programming
void perror(), exit();
21
예제 프로그램 (12)
/* two semaphores in a set
index 0 - incremented when producer
- tested and decremented by
if buffer has been reset
index 1 - incremented when consumer
- tested and decremented by
if consumer is done.
*/
has reset buffer
consumer to check
has read buffer
producer to check
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);
Linux System Programming
}
22
예제 프로그램 (13)
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
*/
Linux System Programming
shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
shmctl(shmid, 0, IPC_RMID);
23
예제 프로그램 (14)
// 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
- tested and decremented by
if buffer has been reset
index 1 - incremented when consumer
- tested and decremented by
Linux System Programming
if consumer is done.
*/
has reset buffer
consumer to check
has read buffer
producer to check
24
예제 프로그램 (15)
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);
}
Linux System Programming
25
예제 프로그램 (16)
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);
}
Linux System Programming
26