수색…


소개

프로세스 간 통신 (IPC) 메커니즘을 통해 서로 다른 독립 프로세스가 서로 통신 할 수 있습니다. 표준 C는 IPC 메커니즘을 제공하지 않습니다. 따라서 이러한 모든 메커니즘은 호스트 운영 체제에 의해 정의됩니다. POSIX는 광범위한 IPC 메커니즘을 정의합니다. Windows는 다른 세트를 정의합니다. 및 다른 시스템은 자체 변종을 정의합니다.

세마포어

세마포어는 두 개 이상의 프로세스간에 작업을 동기화하는 데 사용됩니다. POSIX는 세 개의 다른 세마포어 함수를 정의한다.

  1. 'System V semctl() , semop() , semget() .
  2. '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

이 프로그램을 컴파일하고 실행하면 매번 동일한 출력이 제공됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow