C Language
프로세스 간 통신 (IPC)
수색…
소개
프로세스 간 통신 (IPC) 메커니즘을 통해 서로 다른 독립 프로세스가 서로 통신 할 수 있습니다. 표준 C는 IPC 메커니즘을 제공하지 않습니다. 따라서 이러한 모든 메커니즘은 호스트 운영 체제에 의해 정의됩니다. POSIX는 광범위한 IPC 메커니즘을 정의합니다. Windows는 다른 세트를 정의합니다. 및 다른 시스템은 자체 변종을 정의합니다.
세마포어
세마포어는 두 개 이상의 프로세스간에 작업을 동기화하는 데 사용됩니다. POSIX는 세 개의 다른 세마포어 함수를 정의한다.
- 'System V
semctl()
,semop()
,semget()
. - 'POSIX 세마포어'-
sem_close()
,sem_destroy()
,sem_getvalue()
,sem_init()
,sem_open()
,sem_post()
,sem_trywait()
,sem_unlink()
.
이 절에서는 System V IPC 세마포를 Unix System V에서 시작 했으므로 그렇게 설명합니다.
먼저 필요한 헤더를 포함시켜야합니다. POSIX의 이전 버전에서는 #include <sys/types.h>
; 현대의 POSIX와 대부분의 시스템은 그것을 필요로하지 않습니다.
#include <sys/sem.h>
그런 다음 부모뿐만 아니라 자식 모두에 키를 정의해야합니다.
#define KEY 0x1111
이 키는 두 프로그램에서 동일해야하거나 동일한 IPC 구조를 참조하지 않습니다. 값을 하드 코딩하지 않고 동의 한 키를 생성하는 방법이 있습니다.
그런 다음 컴파일러에 따라 세마포어 작업을 위해 유니온을 선언하여이 단계를 수행해야 할 수도 있고하지 않을 수도 있습니다.
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
다음으로 try ( semwait
) 및 raise ( semsignal
) 구조를 정의하십시오. 이름 P와 V는 네덜란드 출신이다.
struct sembuf p = { 0, -1, SEM_UNDO}; # semwait
struct sembuf v = { 0, +1, SEM_UNDO}; # semsignal
이제, IPC 세마포어의 ID를 얻는 것으로 시작하십시오.
int id;
// 2nd argument is number of semaphores
// 3rd argument is the mode (IPC_CREAT creates the semaphore set if needed)
if ((id = semget(KEY, 1, 0666 | IPC_CREAT) < 0) {
/* error handling code */
}
부모에서 카운터가 1이되도록 세마포어를 초기화합니다.
union semun u;
u.val = 1;
if (semctl(id, 0, SETVAL, u) < 0) { // SETVAL is a macro to specify that you're setting the value of the semaphore to that specified by the union u
/* error handling code */
}
이제, 필요에 따라 세마포어를 감소 시키거나 증가시킬 수 있습니다. 임계 영역의 시작 부분에서 semop()
함수를 사용하여 카운터를 감소시킵니다.
if (semop(id, &p, 1) < 0) {
/* error handling code */
}
세마포어를 증가 시키려면 &p
대신 &v
를 사용하십시오.
if (semop(id, &v, 1) < 0) {
/* error handling code */
}
모든 함수는 성공시 0
을 반환하고 실패시 -1
을 반환합니다. 이러한 반환 상태를 확인하지 않으면 심각한 문제가 발생할 수 있습니다.
Example 1.1 : 스레드를 사용한 레이싱
아래의 프로그램은 자식 프로세스를 fork
하고 부모와 자식 모두 동기화없이 터미널에 문자를 출력하려고 시도합니다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main()
{
int pid;
pid = fork();
srand(pid);
if(pid < 0)
{
perror("fork"); exit(1);
}
else if(pid)
{
char *s = "abcdefgh";
int l = strlen(s);
for(int i = 0; i < l; ++i)
{
putchar(s[i]);
fflush(stdout);
sleep(rand() % 2);
putchar(s[i]);
fflush(stdout);
sleep(rand() % 2);
}
}
else
{
char *s = "ABCDEFGH";
int l = strlen(s);
for(int i = 0; i < l; ++i)
{
putchar(s[i]);
fflush(stdout);
sleep(rand() % 2);
putchar(s[i]);
fflush(stdout);
sleep(rand() % 2);
}
}
}
출력 (1 회) :
aAABaBCbCbDDcEEcddeFFGGHHeffgghh
(2 차) :
aabbccAABddBCeeCffgDDghEEhFFGGHH
이 프로그램을 컴파일하고 실행하면 매번 다른 출력이 나옵니다.
Example 1.2 : 세마포어로 레이싱 피하기
예제 1.1 을 수정하여 세마포어를 사용하면 다음과 같은 결과를 얻을 수 있습니다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define KEY 0x1111
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
struct sembuf p = { 0, -1, SEM_UNDO};
struct sembuf v = { 0, +1, SEM_UNDO};
int main()
{
int id = semget(KEY, 1, 0666 | IPC_CREAT);
if(id < 0)
{
perror("semget"); exit(11);
}
union semun u;
u.val = 1;
if(semctl(id, 0, SETVAL, u) < 0)
{
perror("semctl"); exit(12);
}
int pid;
pid = fork();
srand(pid);
if(pid < 0)
{
perror("fork"); exit(1);
}
else if(pid)
{
char *s = "abcdefgh";
int l = strlen(s);
for(int i = 0; i < l; ++i)
{
if(semop(id, &p, 1) < 0)
{
perror("semop p"); exit(13);
}
putchar(s[i]);
fflush(stdout);
sleep(rand() % 2);
putchar(s[i]);
fflush(stdout);
if(semop(id, &v, 1) < 0)
{
perror("semop p"); exit(14);
}
sleep(rand() % 2);
}
}
else
{
char *s = "ABCDEFGH";
int l = strlen(s);
for(int i = 0; i < l; ++i)
{
if(semop(id, &p, 1) < 0)
{
perror("semop p"); exit(15);
}
putchar(s[i]);
fflush(stdout);
sleep(rand() % 2);
putchar(s[i]);
fflush(stdout);
if(semop(id, &v, 1) < 0)
{
perror("semop p"); exit(16);
}
sleep(rand() % 2);
}
}
}
산출:
aabbAABBCCccddeeDDffEEFFGGHHgghh
이 프로그램을 컴파일하고 실행하면 매번 동일한 출력이 제공됩니다.