1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
리눅스(우분투 10.10) 공유 메모리 예제

// 부모, 자식 프로세스간 공유 메모리 사용 예제

// shmget() 함수로 공유메모리를 생성
// shmat() 함수로 공유메모리에 접근
// shmdt() 함수로 공유메모리와의 접속을 끊음
// shmctl() 함수로 공유메모리를 제어

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <time.h>

// sys/shm.h에 공유메모리와 관련된 구조체와 함수들이 정의되어 있음
// 공유메모리를 shmid_ds 라는 구조체로 관리
// struct shmid_ds
// {
//     struct         ipc_perm shm_perm;    // 퍼미션
//     int            shm_segsz;            // 메모리 공간의 크기
//     time_t         shm_dtime;            // 마지막 attach 시간
//     time_t         shm_dtime;            // 마지막 detach 시간
//     time_t         shm_ctime;            // 마지막 변경 시간
//     unsigned short shm_cpid;             // 생성프로세스의 pid
//     unsigned short shm_lpid;             // 마지막으로 작동한 프로세스의 pid
//     short          shm_nattch;           // 현재 접근한 프로세스의 수
// };
// shm_perm   공유메모리는 여러 개의 프로세스가 동시접속 하므로
//            접근권한을 분명히 명시하여야 한다.
// shm_segsz  할당된 메모리 바이트의 크기
// shm_atime  가장 최근의 프로세스가 접근한 시간
// shm_dtime  가장 최근의 프로세스가 접속을 끊은 시간
// shm_ctime  마지막으로 이 구조체가 변경된 시간
// shm_cpid   이 구조체를 생성한 프로세스의 pid
// shm_lpid   마지막으로 작동을 수행한 프로세스의 pid
// shm_nattch 현재 접근되어 있는 프로세스의 수


#define SHARED_MEMORY_KEY 1234
#define INIT_VALUE 5 // 공유 메모리의 초기값
#define MAX_VALUE 10 // 공유 메모리의 최대값
#define MIN_VALUE 0  // 공유 메모리의 최소값
#define RAND_DISTANCE 5 // 프로세스가 쉴 시간
//                      // 즉, rand 함수의 범위를 지정하기위해
//
// 공유 메모리를 사용하기 위해서는 고유의 key 가 필요
// 공유 메모리를 생성할 때 특정한 key 값을 주어 생성하고
// 접근할 때에도 같은 key 값으로 접근 가능
// key 값은 공유 메모리를 구분하기 위해서도 필요

int main()
{
    int shmid; // 공유메모리의 id를 저장하기 위한 변수
    int pid;   // 자식 프로세스와 부모프로세스를 구분하기 위한 변수
    int *cal_num;
    int sleep_time=0;
    int status;
    int seed1, seed2; // 각 프로세스마다 rand() 함수의 시드값이 달라야 하기 때문에
					  // seed 변수를 두개로 선언

    srand(time(NULL));
    seed1 = rand();  // rand() 함수 초기화
    seed2 = rand();  // rand() 함수 초기화

    // make space that shared-memory
	// 공유 메모리 생성 부분
	//
	// int shmget(key_t key, int size, int shmfig)
	//
	// key :     Shared Memory를 접근하기 위한 Key값
	// size :    메모리의 최소 사이즈.
	//           새로운 메모리를 생성한다면 크기를 반드시 명시해야함
	//           이미 존재하는 메모리를 참조하는 것이라면, 0으로 명시
	//
	// shmfig :  공유 메모리의 접근 권한과, 생성방식을 명시하기 위해
	//           파일 권한과 동일하게 읽기, 쓰기 권한 지정 가능
	//           사용 가능한 생성 방식은 다음과 같다.
	//           
	//           IPC_CREAT : 생성하려는Key 값의 공유메모리가 없는 경우
	//                      새로운 공유 메모리를 만든다.
	//           IPC_EXCL : IPC_CREAT 와 같이 사용되며, 
	//                     공유메모리 공간이 이미 존재하는 경우
	//                      error 를 돌려주고, 메모리에 접근할 수 없게 됨
	//  
	// 반환 값 : 메모리 생성 성공하는 경우 공유메모리의 id 반환.
	//           메모리 생성 실패하는 경우 -1 반환.
	//           shmfig IPC_EXCL 인 경우, 메모리가 존재할 경우 error 반환.
	//
	// int 형의 사이즈만큼
	// 권한은 모두 접속가능하고, 
	// 만약 메모리가 생성되지 않은 경우 새로 생성하는 옵션 사용
	// 
    shmid = shmget((key_t)SHARED_MEMORY_KEY, sizeof(int), 0666 | IPC_CREAT);
    if(shmid == -1){
        perror("shmget failed : ");
        exit(0);
    }

	// 공유메모리 접속하는 부분
	//
	// void * shmat(int shmid, const void *shmaddr, int shmfig)
	//
	// int shmid :           shmget 함수를 이용해 얻은 공유메모리 ID
	//
	// const void *shmaddr : 메모리가 붙을 주소를 명시하기 위해 사용.
	//                       0을 사용하면 커널이 알아서 지정.
	//                       보통의 경우 0을 사용.
	//
	// int shmfig :          해당 공유메모리에 대하여 읽기전용 혹은
	//                       읽기/쓰기 모드를 지정 할 수 있다.
	//                       SHM_RDONLY 를 넘길 경우 읽기 전용으로 열고,
	//                       아무 값도 지정하지 않는 경우 
	//                       읽기/쓰기 가능 모드로 열게 된다
	//
	// 반환 값 :             성공한 경우 해당 메모리의 포인터 반환.
	//                       실패한 경우 -1 반환.
	//
	// 다음은 void 포인터 형의 메모리를 int 포인터 형으로 캐스팅
	//
    cal_num = (int *)shmat(shmid, NULL, 0);
    if(cal_num ==(int *)-1){
        perror("shmat failed : ");
        exit(0);
    }
    *cal_num = INIT_VALUE;

    // make child process
    pid = fork();

    //child process
	// 자식 프로세스가 동작하는 부분
	// rand 함수로 생성된 시간을 쉬었다가 공유메모리에 값을 1증가시킴
	// 프로세스가 끝나면 shmit 함수를 이용해 공유메모리와의 접속을 끊음
	//
	// int shmdt(const void* shmaddr)
	//
	// shmaddr : 공유메모리와의 연결을 끊을 Local 메모리의 포인터
	// 반환 값 : 성공할 경우 0 반환
	//           실패한 경우 -1 반환
	//
    if(pid == 0){
        srand(seed2);
        while(1){
            if((*cal_num) >= MAX_VALUE || (*cal_num)<= MIN_VALUE){
                break;
            }
            *cal_num = *cal_num + 1;
            printf("child : I'm %d sec sleep. plus 1. current value %d\n", sleep_time, *cal_num);
            sleep_time = (rand()%RAND_DISTANCE) +1;
            sleep(sleep_time);
        }
        if((*cal_num) >= MAX_VALUE){
            puts("child : I'm winner\n");
        }
        else{
            puts("child : I'm looser\n");
        }
        shmdt(cal_num);
    }
    // parent process
    // 부모 프로세스
    // 자식 프로세스와 다른점은 shmctl 함수를 사용해
    // 공유메모리를 제거
    // 
    // int shmctl(int shmid, int cmd, struct shmid_ds *buf)
    // 
    // shmid :   공유 메모리의 ID
    // cmd :     원하는 제어작업 명시.
    // 
    //           IPC_STAT : 공유메모리 공간에 관한 정보를
    //                      가져오기 위해 사용. 
    //                      정보는 buf 에 저장된다.
    // 
    //           IPC_SET : 공유메모리 공간에 대한 사용자 권한을
    //                     변경한다. 
    //                     사용자 권한을 변경하기 위해서는
    //                     슈퍼유저, 혹은 사용자 권한을 가지고
    //                     있어야 한다.
    // 
    //           IPC_RMID : 공유메모리 공간을 삭제하기 위해서 사용
    //                      이 명령을 사용한다고 해서 곧바로 
    //                      공유메모리가 삭제되는 것은 아니며,
    //                      공유메모리에 접속되어 있는 프로세스가
    //                      0 일 때까지 기다렸다가 삭제.
    // 
    // *buf :    공유 메모리의 정보를 구하고 싶은 경우,
    //           정보를 저장할 포인터를 같이 넘긴다.
    //           buf 에 공유 메모리의 정보가 저장된다.
    // 반환 값 : 성공할 경우 0 반환.
    //           실패한 경우 -1 반환
    // 
    // 
    // 
    else{
        while(1){
            srand(seed1);
            if((*cal_num) >= MAX_VALUE || (*cal_num)<= MIN_VALUE){
                break;
            }
            *cal_num = *cal_num - 1;
            printf("parent :  I'm %d sec sleep. minus 1. current value: %d\n", sleep_time, *cal_num);
            sleep_time = (rand()%RAND_DISTANCE) +1;
            sleep(sleep_time);
        }
        if((*cal_num) >= MAX_VALUE){
            puts("parent : I'm looser\n");
        }
        else{
            puts("parent : I'm winner\n");
        }
        shmdt(cal_num);
        shmctl(shmid, IPC_RMID, NULL);
        waitpid(pid, &status, 0); // 자식 프로세스를 기다리기 위해서
    }
    return 0;
}


'C언어' 카테고리의 다른 글

c++ 공부 요점 정리 2  (0) 2013.11.11
리눅스(우분투 10.10) 공유 메모리 예제 2  (0) 2013.11.07
bind 에러 해결 방법  (0) 2013.10.31
다중 입출력 함수 select  (0) 2013.10.28
c++ 공부 요점정리 1  (0) 2013.10.26
Posted by 뮹실이

최근에 달린 댓글

06-15 23:14
Yesterday
Today
Total