인프런 커뮤니티 질문&답변

damingu님의 프로필 이미지
damingu

작성한 질문수

리눅스 IPC 프로그래밍 - 이론과 실습

POSIX named semaphore 자원이 제대로 해지되지 못한 상태로 프로세스가 종료됐을 때 해당 semaphore 재사용 방법

작성

·

14

0

안녕하세요.

커리어를 위해 해당 업무를 수강하는 개린이(개발자 어린이)입니다.

구현 중 해결되지 못한 사항이 있어 질문 남깁니다.

현재 구현하고 있는 상황은 두 개의 프로세스(A.exe, B.exe)가 임계영역에 접근하기 위해 posix named semaphore를 사용해 동시성을 지키고 있는 예제를 만들었습니다. named semaphore를 1개 만들어 두 개의 프로세스에 번갈아 소유권을 넘겨 임계영역에 접근하는 예제입니다.

따라서 두 프로세스의 코드는 동일합니다.

같은 이름으로 만들어진 named semaphore가 있다면 EEXIST 에러를 조건문으로 걸어 이미 생성된 named semaphore를 사용하도록 예외처리를 해놓은 상태입니다.

여기서 하나의 프로세스(B.exe)가 named semaphore의 소유권을 가지고 있던 상태에서 갑작스러운 상황에 비정상적으로 종료된다면, 즉 named semaphore의 자원을 정상적으로 sem_post(sem) 하지 못한 상태에서 프로세스가 종료되는 상황에서 다시 해당 프로세스를 동작시켰을 때, 기존에 사용됐던 named semaphore가 정상 동작하지 않는 것을 확인했습니다.

제가 생각했을 땐 비정상적으로 프로세스가 종료되면서 메모리 어딘가에 해당 named semaphore 주소값이 있고 그 주소값을 가져오지 못해 생기는 메모리 낭비의 영역인 것 같습니다.

이런 경우에, 프로세스가 비정상적으로 종료된 경우에 같은이름으로 선언된 naemd semaphore를 재사용하는 방법이나 예외처리나 파라미터 flag 값들이 있다면 지식을 나눠주시면 감사하겠습니다.

 

답변 2

0

런잇(ProgCoach4U)님의 프로필 이미지
런잇(ProgCoach4U)
지식공유자

안녕하세여 damingu님.

질문 글에서 설명해주신 것처럼 프로세스가 비정상종료되면 예기치 못한 일들이 생깁니다. 그 중 하나가 소유하고 있던 공유 자원에 대한 종료 처리를 제대로 할 수 없다는 것입니다. 이런 경우를 대비하기 위해 코드 수준에서 어떤 예외처리를 하는 것보다는 아예 이런 일이 발생하지 않도록 구현하는 방법을 택하고는 합니다.

바로 semaphore를 생성하는 역할을 담당하는 프로세스와 이미 생성된 semaphore를 사용하는 프로세스로 나누는 것이죠. 하나의 프로그램을 작성했다 하더라도 프로그램을 실행하면서 인자로 역할을 전달해 서로 다른 동작을 할 수 있도록 하는 것이죠. 예를 들어 test라는 실행 파일을 실행하면서 ./test master./test slave와 같이 역할을 부여하는 것이죠. 이 프로그램 인자의 값에 따라 semaphore를 생성해 사용하거나 있는 것을 사용하도록 하는 방법입니다.

 

0

안녕하세요, 인프런 AI 인턴입니다. damingu님.

POSIX named semaphore를 사용하여 두 개의 프로세스가 임계 영역에 접근하는 예제를 구현하고 계신군요. 질문하신 내용은 한 프로세스가 비정상적으로 종료되었을 때 semaphore를 재사용하는 방법에 관한 것입니다.

비정상적인 종료 시 semaphore를 정상적으로 해제하거나 초기화하는 문제는 실제 개발 환경에서 중요한 이슈입니다. 몇 가지 방법을 통해 해결할 수 있습니다:

  1. Semaphore 초기화: 프로세스가 시작할 때 semaphore를 초기화해 보세요. semaphore 이름을 통해 이미 기존에 생성된 semaphore인지 확인할 수 있습니다. sem_open() 함수를 사용할 때 O_CREAT | O_EXCL 플래그를 함께 사용하여 semaphore가 이미 존재하면 다른 방법으로 초기화하거나 할 수 있게끔 제어합니다.

  2. 시스템 재시작 시 초기화: 시스템이 다시 시작되면 semaphore와 관련된 리소스를 초기화해야 합니다. 이는 보통 시스템의 초기화 루틴에서 수행됩니다.

  3. 긴급 종료 처리: SIGTERM 같은, 프로세스가 비정상 종료될 때를 대비해 signal handler를 사용하여 semaphore를 해제하는 코드를 작성합니다.

  4. 파일 기반 semaphore 사용: semaphore가 파일 기반으로 구현되어 있는 경우, 파일 시스템의 일관성을 신뢰할 수 없을 때 파일을 삭제하고 새로 생성하는 방법도 있습니다.

이 외에도 semaphore가 비정상 상태가 되는 경우를 대비하여 다른 예외 처리 방법을 생각해 볼 수 있습니다. 더 구체적인 코드나 에러 메시지를 남겨주시면 보다 상세한 도움을 드릴 수 있습니다.

관련 질문 링크를 참고하시기 바랍니다:
- 프로세스 생성에 대한 질문입니다

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

damingu님의 프로필 이미지
damingu
질문자

아래와 같은 코드로 위에서 알려준 예외처리를 어떻게 할 수 있는지도 알려주면 좋을 것 같습니다.

#include <iostream>
#include <fcntl.h>           // O_CREAT, O_EXCL
#include <sys/mman.h>        // mmap, shm_open
#include <semaphore.h>       // sem_open, sem_wait, sem_post
#include <unistd.h>          // ftruncate, close
#include <cstring>           // strerror
#include <sys/stat.h>        // S_IRWXU
#include <cstdlib>           // EXIT_FAILURE

#define SHM_NAME "/my_shared_memory7"
#define SEM_NAME "/my_semaphore7"
#define SHM_SIZE sizeof(int)

void error_exit(const char* msg) {
    std::cerr << msg << ": " << strerror(errno) << std::endl;
    exit(EXIT_FAILURE);
}

int main() {
    // 공유 메모리 설정
    int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRWXU);
    if (shm_fd == -1) error_exit("shm_open failed");
    if (ftruncate(shm_fd, SHM_SIZE) == -1) error_exit("ftruncate failed");

    int* shared_data = (int*)mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_data == MAP_FAILED) error_exit("mmap failed");

    // 세마포어 초기화
    sem_t* sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, S_IRWXU, 1);
    if (sem == SEM_FAILED) {
      if(errno == EEXIST) {
        sem = sem_open(SEM_NAME, 1);
        if (sem == SEM_FAILED) error_exit("sem_open failed");
      }else { 
        error_exit("sem_open failed");
      }
    }
    while(1){     
        // 공유 메모리 쓰기
        if (sem_wait(sem) == -1) error_exit("sem_wait failed");  // 세마포어 획득
        *shared_data += 1;  // 공유 메모리에 값 증가
        std::cout << "Shared Data: " << *shared_data << std::endl;
        sleep(1);
        if (sem_post(sem) == -1) error_exit("sem_post failed");  // 세마포어 해제
    }
    // 자원 정리
    if (munmap(shared_data, SHM_SIZE) == -1) error_exit("munmap failed");
    if (close(shm_fd) == -1) error_exit("close failed");
    if (sem_close(sem) == -1) error_exit("sem_close failed");

    // 마지막 프로세스가 실행될 때 공유 메모리와 세마포어 제거
    if (shm_unlink(SHM_NAME) == -1) std::cerr << "Warning: shm_unlink failed" << std::endl;
    if (sem_unlink(SEM_NAME) == -1) std::cerr << "Warning: sem_unlink failed" << std::endl;

    return 0;
}
damingu님의 프로필 이미지
damingu

작성한 질문수

질문하기