이 영역을 누르면 첫 페이지로 이동
Arc 블로그의 첫 페이지로 이동

Arc

페이지 맨 위로 올라가기

Arc

[Unix Programming] Record Locking

  • 2021.12.02 02:01
  • Computer Science/OS
글 작성자: SeoArc

Record Locking은 두 명 이상의 파일 사용자가 동시에 정보를 업데이트하려고 할 때 발생할 수 있는 오류, 즉 경쟁상태를 방지하기 위해 파일 또는 파일의 일부를 잠그는 것이다.

 

Record Locking

read lock

- 여러 프로세스들이 같은 구역 동시에 설정 가능(write lock 적용 불가)

write lock

- 다른 프로세스들의 읽기나 쓰기 록을 불허

 

record lock을 걸기 위해서 fcntl이란 함수를 사용한다.

#include <fcntl.h>

int fcntl(int filedes, int cmd, struct flock *ldata);

여기서 filedes는 file descriptor를 의미하고, cmd는 F_GETLK, F_SETLK, F_SETLKW 을 넣어 설정할 수 있다.

struct flock은 lock의 세부사항을 설정하는 구조체 변수이다.

 

cmd

- F_GETLK: ldata를 통해 lock 정보를 획득

- F_SETLK: lock을 적용하고 즉시 return, lock 제거에도 사용

- F_SETLKW: lock 적용, 타 process에 의해 봉쇄되면 sleep

 

struct flock

struct flock {
    short l_type;	// lock의 유형
    short l_whence;	// 변위 유형
    off_t l_start;	// offset
    off_t l_len;	// length
    pid_t l_pid;	// F_GETLK인 경우에 locking process의 pid 값을 저장
};

 

l_whence는 어느 위치에서부터 lock를 걸지 결정하는 변수이다. 파일의 처음, 마지막, 파일 포인터(r/w pointer)의 위치 중 어디서부터 시작할 건지 정한다.

l_start는 얼마만큼 떨어진 거리에서부터 lock을 걸 건지 시작점을 정한다.

l_len는 lock을 걸 길이를 정한다. (byte 단위)

l_pid는 F_GETLK인 경우, 즉 lock를 획득한 프로세스의 id가 저장된다.

 

lock의 유형

- F_RDLCK: read lock

- F_WRLCK: write lock

- F_UNLCK: unlock

 

이제 위 함수를 사용하여 locking 예시를 살펴보면

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>

main()
{
    int fd;
    struct flock my_lock;
    
    /* write lock의 인수를 지정 */
    my_lock.l_type = F_WRLCK;		// write lock
    my_lock.l_whence = SEEK_SET;		// 현재 r/w pointer 기준
    my_lock.l_start = 0;			// 기준점에서 0 떨어진 곳
    my_lock.l_len = 10;			// lock될 segment의 길이
    
    /* 파일 개방 */
    fd = open("locktest", O_RDWR);
    
    /* 처음 10bytes locking */
    if (fcntl(fd, F_SETLKW, &my_lock) == -1) {
    	perror("parent: locking");
        exit(1);
    }
    printf("parent locked record\n");
    
    switch(fork()) {
        case -1:		/* 오류 */
            perror("fork");
            exit(1);
        case 0:			/* 자식 */
            my_lock.l_len = 5;
            if (fcntl(fd, F_SETLKW, &my_lock) == -1) {
                perror("child: locking");
                exit(1);
            }
            printf("child: locked\n");
            printf("child: exiting\n");
            exit(0);
    }
    
    sleep(5);
    
    /* exit. lock이 해제된다 */
    printf("parent: exiting\n");
    exit(0);
}

위 코드를 실행시키면 아래와 같이 결과가 나오는 것을 확인할 수 있다

parent : locked record
parent : exiting
child : locked
child : exiting

 

아래는 fcntl 함수를 이용한 unlocking 예제이다.

my_lock.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &my_lock) == -1) {
    perror("parent: unlocking");
    exit(1);
}

 

record locking에 대한 내용을 알아보았다.

locking을 할 때는 항상 교착상태(deadlock)이 발생하지 않도록 주의해야 한다.

마지막으로 교착상태에 대한 코드 예시를 살펴보면

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

main() {
    int fd;
    struct flock first_lock;
    struct flock second_lock;
    
    first_lock.l_type = F_WRLCK;
    first_lock.l_whence = SEEK_SET;
    first_lock.l_start = 0;
    first_lock.l_len = 10;
    
    second_lock.l_type = F_WRLCK;
    second_lock.l_whence = SEEK_SET;
    second_lock.l_start = 10;
    second_lock.l_len = 5;
    
    fd = open("locktest", O_RDWR);
    
    if (fcntl(fd, F_SETLKW, &first_lock) == -1) {
        fatal("A");
    }
    printf("A: lock succeeded (proc %d)\n", getpid());
    
    switch (fork()) {
        case -1:		/* 오류 */
            fatal("error on fork");
        case 0:			/* 자식 */
            if (fcntl(fd, F_SETLKW, &second_lock) == -1) {
                fatal("B");
            }
            printf("B: lock succeeded (proc %d)\n", getpid());
            
            if (fcntl(fd, F_SETLKW, &first_lock) == -1) {
                fatal("C");
            }
            printf("C: lock succeeded (proc %d)\n", getpid());
            exit(0);
        default:		/* 부모 */
            printf("parent sleeping\n");
            sleep(10);
            
            if (fcntl(fd, F_SETLKW, &second_lock) == -1) {
                fatal("D");
            }
            printf("D: lock succeeded (proc %d)\n", getpid());
    }
}

위 예제를 살펴보면 첫번째는 0부터 9까지, 두번째는 10부터 14까지 lock을 획득하도록 되어있다.

parent process는 첫번째 lock을 획득한 후 두번째를 획득하려하고,

child process는 두번째 lock을 획득한 후 첫번째를 획득하려고 하는 상황이 만들어진다.

'Computer Science > OS' 카테고리의 다른 글

[Unix Programming] ipcs & ipcrm  (0) 2021.12.13
[Unix Programming] Shared Memory  (0) 2021.12.13
[Unix Programming] Semaphore  (0) 2021.12.04
[Unix Programming] Message Passing  (0) 2021.12.04
[Unix Programming] IPC 기본 개념  (0) 2021.12.03

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [Unix Programming] Shared Memory

    [Unix Programming] Shared Memory

    2021.12.13
  • [Unix Programming] Semaphore

    [Unix Programming] Semaphore

    2021.12.04
  • [Unix Programming] Message Passing

    [Unix Programming] Message Passing

    2021.12.04
  • [Unix Programming] IPC 기본 개념

    [Unix Programming] IPC 기본 개념

    2021.12.03
다른 글 더 둘러보기

정보

Arc 블로그의 첫 페이지로 이동

Arc

  • Arc의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록

카테고리

  • 분류 전체보기 (106)
    • Language (28)
      • C++ (0)
      • C# (0)
      • Java (28)
    • Algorithm (47)
      • Algorithm (15)
      • Data Structure (6)
      • PS (26)
    • Computer Science (22)
      • Design Pattern (1)
      • Network (14)
      • OS (7)
    • Game (0)
      • Unity (0)
    • Backend (3)
      • Spring (1)
      • JPA (2)
    • DB (0)
      • SQL (0)
    • DevOps (2)
      • AWS (0)
      • Docker (2)
      • Jenkins (0)
      • Nginx (0)
    • Software Engineering (4)
      • OOP (4)
    • AI (0)
      • Machine Learning (0)
    • Others (0)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • 자바
  • java
  • 그래프
  • network
  • 알고리즘
  • 네트워크
  • graph
  • algorithm

나의 외부 링크

정보

SeoArc의 Arc

Arc

SeoArc

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. © SeoArc. Designed by Fraccino.

티스토리툴바