뮤텍스 락과 비슷한 개념이다
critical section 을 피하기 위해 사용하는 기법이다
ㅁ레코드 락킹(advisory locking): 여러 프로세스가 동일한 파일을 동시에 다룰 때 충돌을 방지하기 위해 사용하는 방법 (critical section avoidance)
multiple reader, single writer
1 .읽기 락: 여러 프로세스가 동시에 읽을 수 있도록 허용하지만, 쓰기 락은 적용되지 않게 함
2. 쓰기 락: 특정 프로세스가 쓰기 작업을 하는 동안 다른 프로세스가 해당 구역을 읽거나 쓰지 못하게 막음. 한 구역에 하나의 쓰기 록만 존재 가능
fcntl 함수는 파일 기술자(fd)를 통해 파일의 여러 속성을 제어하는 다목적 함수이다
ㅇ int fcntl (int filedes, int cmd, struct flock* ldata): 파일에 락을 적용하는 함수
- filedes : 유효한 개방된 파일기술자. 읽기 락인 경우 O_RDONLY나 O_RDWR로 개방. 쓰기 락을 위해서는 O_WRONLY나 O_RDWR로 개방
- cmd : 파일에 대한 특정 작업을 설정하는 명령어
<cmd에 들어가는 기능>
• F_GETLK : ldata를 통해 전달된 현재 설정 락 정보를 획득
• F_SETLK : 파일에 락을 설정하고, 불가능하면 즉시 -1을 반환
• F_SETLKW : 파일에 락을 설정하고, 만약 다른 프로세스가 점유중이면 대기(sleep)
(레코드 락킹에 필요한 struct flock 구조체)
struct flock {
short l_type; /* 락의 유형: F_RDLCK(읽기 락), F_WRLCK(쓰기 락), F_UNLCK(락 해제) */
short l_whence; /* lseek와 동일하다, 기준 위치: SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* 시작 오프셋 (바이트 단위) */
off_t l_len; /* 락의 길이인 세그먼트 크기 (바이트 단위), 0이면 파일 끝까지 */
pid_t l_pid; /* 락을 설정한 PID, 명령에 의해 설정 */
};
(예시 코드)
struct flock my_lock;
my_lock.l_type = F_WRLCK; // 쓰기 락 설정
my_lock.l_whence = SEEK_CUR; // 현재 파일 위치를 기준으로
my_lock.l_start = 0; // 락 시작 위치를 현재 위치로부터 0바이트
my_lock.l_len = 512; // 512바이트 길이로 잠금
// F_SETLKW cmd를 사용하여 락을 설정
// 다른 프로세스가 해당 구역을 이미 잠가놓은 경우, 락이 해제될 때까지 대기
fcntl(fd, F_SETLKW, &my_lock);
(test1.c 코드)
▪ 락 정보는 fork호출에 의해 계승되지 않음
▪ fcntl호출의 파일포인터를 변경시키지 않음
▪ 한 프로세스에 속한 모든 락은 그 프로세스가 죽을 때 자동적으로 제거됨
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int fd;
struct flock my_lock;
struct flock b_lock;
my_lock.l_type = F_WRLCK;
my_lock.l_whence = SEEK_SET;
my_lock.l_start = 0;
my_lock.l_len = 10;
fd = open("testdata", O_RDWR);
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(2);
printf("parent: unlocking\n");
my_lock.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &my_lock) == -1) {
printf("parent : unlocking");
exit(1);
}
exit(0);
return 0;
}
(test2.c 코드)
▪ 프로세스는 F_GETLK를 사용해 어느 프로세스가 락을 가지고 있는지 결정할 수 있음
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int fd;
struct flock my_lock;
struct flock b_lock;
my_lock.l_type = F_WRLCK;
my_lock.l_whence = SEEK_SET;
my_lock.l_start = 0;
my_lock.l_len = 10;
fd = open("testdata", O_RDWR);
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(2);
printf("parent: unlocking\n");
my_lock.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &my_lock) == -1) {
printf("parent : unlocking");
exit(1);
}
exit(0);
return 0;
}
(test3.c 코드)
▪ Deadlock Avoidance test
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int fd;
struct flock first_lock, 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("testdata", O_RDWR);
if (fcntl(fd, F_SETLKW, &first_lock) == -1) {
perror("A");
exit(1);
}
printf("A: lock succedded (proc %d)\n", getpid());
switch(fork()) {
case -1 :
perror("error on fork");
exit(1);
case 0 :
if (fcntl(fd, F_SETLKW, &second_lock) == -1) {
perror("B");
exit(1);
}
printf("B: lock succeeded (proc %d)\n", getpid());
if (fcntl(fd, F_SETLKW, &first_lock) == -1) {
perror("C");
exit(1);
}
printf("C: lock succeeded (proc %d)\n", getpid());
exit(0);
default:
printf("parent sleeping\n");
sleep(5);
if (fcntl(fd, F_SETLKW, &second_lock) == -1) {
perror("D");
exit(1);
}
printf("D: lock succeeded (proc %d)\n", getpid());
}
return 0;
}
'Computer Science > UNIX & Linux' 카테고리의 다른 글
[UNIX/Linux] ep10-1+) 메시지 큐 함수 실습 (5) | 2024.11.07 |
---|---|
[UNIX/Linux] ep10-1) 메시지 큐, 공유 메모리 (0) | 2024.11.06 |
[UNIX/Linux] ep9+) 파이프 함수 실습 (0) | 2024.11.04 |
CUDA + RAID 기반 데이터 분산 시뮬레이션 (8) | 2024.10.31 |
[UNIX/Linux] ep9) 파이프 (0) | 2024.10.31 |