[Unix Programming] Record Locking
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 |
댓글
이 글 공유하기
다른 글
-
[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