공유 메모리는 IPC(Inter-Process Communication)의 한 가지 방법으로 프로세스간 통신이 필요할 경우 사용합니다.
공유 메모리를 통한 통신은 둘 이상의 프로세스가 공통 메모리에 액세스 할 수 있는 개념으로
한 프로세스에서 변경한 메모리 공간의 내용을 다른 프로세스에서 접근할 수 있습니다.
공유 메모리의 생성 요청은 최초 공유 메모리 영역을 만드는 프로세스가 커널에 공유 메모리 공간의 할당을 요청함으로써
이루어지며 만들어진 공유 메모리는 커널에 의해서 관리됩니다.
만들어진 공유 메모리는 시스템을 리부팅하거나 직접 공유 메모리의 공간을 삭제시키지 않는 한,
공유 메모리를 사용하는 모든 프로세스가 없어졌다고 하더라도 공유 메모리의 공간은 계속적으로 유지되게 됩니다.
프로세스가 커널에게 공유 메모리 공간을 요청하게 되면,
커널은 공유 메모리 공간을 할당시켜주고 공유 메모리 공간을 관리하기 위해 내부 자료구조를 사용합니다.
공유 메모리 정보들은 shmid_ds라는 구조체에 의해 관리되며 shm.h에 정의되어 있습니다.
공유 메모리를 사용하지 위해서는 아래의 헤더파일을 include 해주어야 합니다.
#include <sys/types.h>
#include <sys/shm.h>
■ shmget
함수 원형: int shmget(key_t key, int size, int shmflg)
- 커널에 공유 메모리 공간을 요청하기 위해 사용하는 시스템 호출 함수
- KEY값은 고유의 공유 메모리임을 나타낸다
- Argument (KEY, MEMORY_MAX_SIZE, 접근권한 | 생성방식)
■ shmmat
함수 원형: void *shmat( int shmid, const void *shmaddr, int shmflg )
- 공유 메모리 공간을 생성한 이후, 공유메모리에 접근할 수 있는 int형의 "식별자"를 얻는다
- 공유 메모리를 사용하기 위해 얻은 식별자를 이용하여 현재 프로세스가 공유 메모리에 접근할 수 있도록 연결하는 작업
- Argument (식별자, 메모리가 붙을 주소 (0을 사용할 경우 커널이 메모리가 붙을 주소를 명시), 읽기/쓰기 모드)
■ shmdt
함수 원형: int shmdt( const void *shmaddr)
- 프로세스가 더이상 공유 메모리를 사용하지 않을 경우 프로세스와 공유 메모리를 분리시키는 작업
- 해당 시스템 호출 함수는 현재 프로세스와 공유 메모리를 분리시킬 뿐, 공유 메모리의 공간을 삭제하지 않는다
- shmdt 가 성공적으로 수행되면 커널은 shmid_ds 의 내용을 갱신, 즉 shm_dtime, shm_lpid, shm_nattch 등의 내용을 갱신 하는데,
shm_dtime 는 가장 최근에 dettach (즉 shmdt 를 사용한)된 시간, shm_lpid 는 호출한 프로세세의 PID, shm_nattch 는 현재 공유 메모리를
사용하는 (shmat 를 이용해서 공유 메모리에 붙어있는) 프로세스의 수를 돌려준다.
■ shmctl
함수 원형: int shmctl(int shmid, int cmd, struct shmid_ds *buf)
- 공유 메모리를 제어하기 위해 사용
- shmid_ds 구조체를 직접 제어함으로써, 해당 공유 메모리에 대한 소유자, 그룹 등의 허가권을 변경하거나, 공유 메모리 삭제,
공유 메모리의 잠금을 설정하거나 헤제하는 작업
- Option
IPC_STAT : 공유 메모리 공간에 관한 정보를 가져오기 위해서 사용된다. 정보는 buf 에 저장된다.
IPC_SET : 공유 메모리 공간에 대한 사용자권한 변경을 위해서 사용된다.
사용자 권한 변경을 위해서는 슈퍼유저 혹은 사용자 권한을 가지고 있어야 한다.
IPC_RMID : 공유 메모리 공간을 삭제하기 위해서 사용된다. 이 명령을 사용한다고 해서 곧바로 사용되는건 아니며,
더이상 공유 메모리 공간을 사용하는 프로세스가 없을 때, 즉 shm_nattch 가 0일때 까지 기다렸다가 삭제된다.
■ 공유 메모리 예제
아래의 코드는 두 프로세스 사이에서 공유 메모리를 통해 데이터를 전달하는 코드의 예를 작성하였습니다.
실제로 프로그램을 아래와 같이 구성하진 않지만 편의를 위해 sleep()을 사용하였습니다.
First Process Shared Memory 및 Second Process Shared Memory 코드를 저는 한 스크립트에 올렸지만,
실행을 하시려면 다른 프로세스에서 접근해야 하므로 각각 다른 프로젝트에 빌드하셔야 합니다.
해당 코드는 First Process가 공유메모리를 만들고 5초 후에 공유메모리에 1의 값을 써주는 작업을하고,
Second Process가 First Process가 만든 공유 메모리를 자신의 프로세스에 연결하고 값을 계속해서 읽다가 1의 값이
읽히는 순간 종료되는 프로그램입니다.
// First 프로세스 - 공유 메모리 Create 및 Write
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
|
////////////////////////////////////
// First Process Shared Memory
////////////////////////////////////
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#define KEY_NUM 1234
#define MEM_SIZE 4096
using namespace std;
int shmid;
static int SharedMemoryCreate();
static int SharedMemoryWrite(char *shareddata, int size);
static int SharedMemoryRead(char *sMemory);
static int SharedMemoryFree(void);
int main(int argc, char *argv[])
{
char buffer[MEM_SIZE] = {1,};
SharedMemoryCreate();
sleep(5);
SharedMemoryWrite(buffer, sizeof(buffer));
return 0;
}
static int SharedMemoryCreate()
{
if((shmid = shmget((key_t)KEY_NUM, MEM_SIZE, IPC_CREAT| IPC_EXCL | 0666)) == -1) {
printf("There was shared memory.");
shmid = shmget((key_t)KEY_NUM, MEM_SIZE, IPC_CREAT| 0666);
if(shmid == -1)
{
perror("Shared memory create fail");
return 1;
}
else
{
SharedMemoryFree();
shmid = shmget((key_t)KEY_NUM, MEM_SIZE, IPC_CREAT| 0666);
if(shmid == -1)
{
perror("Shared memory create fail");
return 1;
}
}
}
return 0;
}
static int SharedMemoryWrite(char *shareddata, int size)
{
void *shmaddr;
if(size > MEM_SIZE)
{
printf("Shared memory size over");
return 1;
}
if((shmaddr = shmat(shmid, (void *)0, 0)) == (void *)-1)
{
perror("Shmat failed");
return 1;
}
memcpy((char *)shmaddr, shareddata, size);
if(shmdt(shmaddr) == -1)
{
perror("Shmdt failed");
return 1;
}
return 0;
}
static int SharedMemoryRead(char *sMemory)
{
void *shmaddr;
char mess[MEM_SIZE] = {0};
if((shmaddr = shmat(shmid, (void *)0, 0)) == (void *)-1)
{
perror("Shmat failed");
return 1;
}
memcpy(sMemory, (char *)shmaddr, sizeof(mess));
if(shmdt(shmaddr) == -1)
{
perror("Shmdt failed");
return 1;
}
return 0;
}
static int SharedMemoryFree(void)
{
if(shmctl(shmid, IPC_RMID, 0) == -1)
{
perror("Shmctl failed");
return 1;
}
printf("Shared memory end");
return 0;
}
|
// Second 프로세스 - 공유 메모리 Connect 및 Read
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
|
///////////////////////////////////////
// Second Process Shared Memory
////////////////////////////////////////
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#define KEY_NUM 1234
#define MEM_SIZE 4096
using namespace std;
int shmid;
static int SharedMemoryInit();
static int SharedMemoryWrite(char *sMemory, int size);
static int SharedMemoryRead(char *sMemory);
int main(int argc, char *argv[])
{
char buffer[MEM_SIZE] = {0,};
SharedMemoryInit();
while(1)
{
SharedMemoryRead(buffer);
if(buffer[0] == 1)
{
cout << "Receive data from shared memory!" << endl;
break;
}
}
return 0;
}
static int SharedMemoryInit()
{
void *shmaddr;
if((shmid = shmget((key_t)KEY_NUM, 0, 0)) == -1)
{
perror("Shmid failed");
}
return 0;
}
static int SharedMemoryWrite(char *sMemory, int size)
{
void *shmaddr;
if((shmaddr = shmat(shmid, (void *)0, 0)) == (void *)-1)
{
perror("Shmat failed");
}
memcpy((char *)shmaddr, sMemory, size);
if(shmdt(shmaddr) == -1)
{
perror("Shmdt failed");
exit(1);
}
return 0;
}
static int SharedMemoryRead(char *sMemory)
{
void *shmaddr;
if((shmaddr = shmat(shmid, (void *)0, 0)) == (void *)-1)
{
perror("Shmat failed");
}
memcpy(sMemory, (char *)shmaddr, sizeof(sMemory));
if(shmdt(shmaddr) == -1)
{
perror("Shmdt failed");
}
return 0;
}
|
'Qt' 카테고리의 다른 글
동적으로 생성한 QTabWidget 및 QTableView 다루기 (1) | 2020.02.04 |
---|---|
pthread_cancel 취소 요청하기 (5) | 2020.01.31 |
Linux 환경 Qwt 라이브러리 설치하기 (0) | 2020.01.29 |
hide(), close() 차이 (0) | 2020.01.28 |
Meta-Object System 이란 (0) | 2020.01.28 |