Superkkt Blog

Code:
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

static int shm_id;
static int sem_id;
static int *num;
static pid_t main_pid;


/* 종료함수 */
void
terminator(void)
{
    /* main process에서만 작동 */
    if(getpid() == main_pid) {
        /* shared memory 제거 */
        shmctl(shm_id, IPC_RMID, NULL);
        shmdt((void *) num);

        /* semaphore 제거 */
        semctl(sem_id, 0, IPC_RMID);
    }
}


int
main(void)
{
    int a;
    pid_t pid;
    struct sembuf in = {0, -1, SEM_UNDO};
    struct sembuf out = {0, 1, SEM_UNDO};

    /* semaphores 초기값을 줄때 사용하는 공용체 */
    union semun {
        int val;
        struct semid_ds *buf;
        ushort *array;
    } argument;

    atexit(terminator);
    main_pid = getpid();

    /* shared memory 생성 */
    if((shm_id = shmget(IPC_PRIVATE, sizeof(int), 0666)) < 0) {
        perror("shmget error");
        exit(1);
    }
    if((num = (int *) shmat(shm_id, 0, 0)) == (void *) -1) {
        perror("shmat error");
        exit(1);
    }
    *num = 0;

    /* semaphores 생성 */
    if((sem_id = semget(IPC_PRIVATE, 1, 0666)) < 0) {
        perror("semget error");
        exit(1);
    }
    argument.val = 1;
    if(semctl(sem_id, 0, SETVAL, argument) == -1) {
        perror("semctl error");
        exit(1);
    }

    pid = fork();

    /* child */
    if(pid == 0) {
        a = 0;
        while(1) {
            fprintf(stderr, "trying to lock in child\n");
            if(semop(sem_id, &in, 1) == -1) {
                perror("semop error");
                exit(1);
            }

            fprintf(stderr, "locked in child\n");
            sleep(2);

            /* lock인 상태에서 프로세스가 종료했을때
             * 커널이 SEM_UNDO를 해서 자동으로 lock
             * 을 풀어주는지 테스트하기 위한 코드
             */
            if(a == 5) {
                fprintf(stderr, "child terminated\n");
                exit(0);
            }

            if(semop(sem_id, &out, 1) == -1) {
                perror("semop error");
                exit(1);
            }
            fprintf(stderr, "unlocked in child\n");
            a++;
            sleep(1);
        }
    }
    else if(pid > 0) {
        a = 0;
        while(1) {
            fprintf(stderr, "trying to lock in parent\n");
            if(semop(sem_id, &in, 1) == -1) {
                perror("semop error");
                exit(1);
            }

            fprintf(stderr, "locked in parent\n");
            sleep(2);

            if(semop(sem_id, &out, 1) == -1) {
                perror("semop error");
                exit(1);
            }
            fprintf(stderr, "unlocked in parent\n");
            sleep(1);
            if(a == 8)
                exit(0);
            a++;
        }
    }

    return 0;
}


부모/자식 프로세스간에 Shared memory와 Semaphores를 사용하는 예제이다. 만약 부모/자식 관계가 아닌프로세스가 공유메모리와 세마포어에 접근하려면 shmget() / semget() 함수를 부를때 이미 만들어진 key를 알아야하기때문에 IPC_PRIVATE를 사용할 수 없다.

소스코드를 통해 확인한바에 따르면 attach된 공유메모리는 자식 프로세스에게 상속된다. 또한 세마포어도 자식이 그대로사용할 수 있는데 세마포어의 경우에는 attack/detach가 없고 단지 id만 알면 쓸 수 있기 때문에 특별히 상속의개념으로 볼 수는 없다.

그리고 자식 프로세스에서 중간에 unlock을 하지않고 lock 상태로 프로그램을 종료하더라도 세마포어 옵션에SEM_UNDO를 사용했기 때문에 커널이 자동으로 unlock을 해준다. SEM_UNDO는 프로그램이 lock을 풀지않고종료(비정상 종료 포함)했을때 커널이 대신 unlock을 해주도록 하는 옵션이다.

세마포어와 공유메모리는 프로그램이 끝날때 반드시 해제를 해줘야한다. 그렇지 않으면 프로그램이 끝나더라도 계속 시스템에남아있게되고 ipcrm 명령어를 사용해서 수동으로 지우거나 시스템을 리부팅해야만 없어진다. 소스코드에서는 exit()시 실행되는함수를 등록해서 부모 프로세스일때만 공유메모리와 세마포어를 해제하도록 코딩하였다.

그리고 세마포어와 공유메모리를 사용하면 한가지 단점이 있는데 프로그램을 SIGKILL을 사용해서 죽이면 세마포어, 공유메모리를 해제할 방법이 없다는것이다. SIGKILL은 잡을수도 없기 때문에...
2006/03/19 16:21 2006/03/19 16:21

trackbacks

trackbacks rss

이 글에는 트랙백을 보낼 수 없습니다

  1. How to use Shared memory and Semaphores.

    Tracked from "hurryon:hurryon" 2006/05/18 15:42 D

    This code describes how to use Shared memory and Semaphores in Linux C programming. This code have come from http://superkkt.com

Leave a Comment