파일 및 레코드 잠금 목차
목표
fcntl() 함수를 이해한다
fcntl() 함수를 사용하여 잠금을 구현한다
fcntl() 함수란?
파일 및 레코드 잠금을 구현하는 시스템 호출
읽기 잠금 : 여러 프로세스가 공유 가능한 읽기 잠금
쓰기 잠금 : 한 프로세스 만이 가질수 있는 쓰기 잠금
fcntl() 함수 설명
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, struct flock *lock);
매개변수
fd : 잠금이 되는 파일 디스크립터
cmd : 잠금 검사 혹은 잠금 설정 (F_GETLK, F_SETLK, F_SETLKW)
F_GETLK : 잠금 복사
F_SETLK : 잠금 설정 혹은 해제
F_SETLKW : 잠금 설정(Blocking 버전) 혹은 해제
flock : 구조체, 잠금 종류, 프로세스 ID, 잠금 위치 등 실질적인 역할
flock 구조체 이해하기
struct flock {
short l_type; // 잠금 종류 : F_RDLCK, F_WRLCK, F_UNLCK
off_f l_start; // 잠금 시작 위치
short l_whence; // 기준 위치 : SEEK_SET, SEEK_CUR, SEEK_END
off_t l_len; // 잠금 길이 : 바이트 수
pid_t l_pid; // 프로세스 번호
}
구조체 변수
l_type : 잠금 형식을 선택
F_RDLCK : 읽기 잠금
F_WRLCK : 쓰기 잠금
F_UNLCK : 잠금 해제
l_start : 잠금 시작 위치를 선정
l_whence : 기준 위치
SEEK_SET : 맨처음 위치
SEEK_CUR : 현제 포인터의 위치
SEEK_END : 맨마지막 위치
l_len : 잠그고자하는 레코드의 길이
l_pid : 프로세스 번호
fcntl ()이용해 파일 잠그기 구현
알고리즘
잠그고자 하는 db생성
생성된 db 질의
생성된 db 수정
db를 수정중에 질의 프로그램이 행당 레코드를 접근하는 경우 읽을 수 없도록 구현
#define MAX 24
struct student {
char name[MAX];
int id;
int score;
};
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include "student.h"
#define START_ID 1401001
/* 학생 정보를 입력받아 데이터베이스 파일에 저장한다. */
int main(int argc, char *argv[])
{
int fd;
struct student record;
if (argc < 2) {
fprintf(stderr, "사용법 : %s file\n", argv[0]);
exit(1);
}
if ((fd = open(argv[1],O_WRONLY |O_CREAT|O_EXCL, 0640))==-1) {
perror(argv[1]);
exit(2);
}
printf("%7s %6s %4s\n", "학번", "이름", "점수");
while (scanf("%d %s %d", &record.id, record.name, &record.score) == 3) {
lseek(fd, (record.id - START_ID) * sizeof(record), SEEK_SET);
write(fd, (char *) &record, sizeof(record) );
}
close(fd);
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "student.h"
#define START_ID 1401001
/* 잠금을 이용한 학생 데이터베이스 질의 프로그램 */
int main(int argc, char *argv[])
{
int fd, id;
struct student record;
struct flock lock;
if (argc < 2) {
fprintf(stderr, "사용법 : %s file\n", argv[0]);
exit(1);
}
if ((fd = open(argv[1], O_RDONLY)) == -1) {
perror(argv[1]);
exit(2);
}
printf("\n검색할 학생의 학번 입력:");
while (scanf("%d", &id) == 1) {
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = (id-START_ID)*sizeof(record);
lock.l_len = sizeof(record);
if (fcntl(fd,F_SETLKW, &lock) == -1) { /* 읽기 잠금 */
perror(argv[1]);
exit(3);
}
lseek(fd, (id-START_ID)*sizeof(record), SEEK_SET);
if ((read(fd, (char *) &record, sizeof(record)) > 0) &&
(record.id != 0))
printf("이름:%s\t 학번:%d\t 점수:%d\n",
record.name, record.id, record.score);
else printf("레코드 %d 없음\n", id);
lock.l_type = F_UNLCK;
fcntl(fd,F_SETLK, &lock); /* 잠금 해제 */
printf("\n검색할 학생의 학번 입력:");
}
close(fd);
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "student.h"
#define START_ID 1401001
/* 잠금을 이용한 학생 데이터베이스 수정 프로그램 */
int main(int argc, char *argv[])
{
int fd, id;
struct student record;
struct flock lock;
if (argc < 2) {
fprintf(stderr, "사용법 : %s file\n", argv[0]);
exit(1);
}
if ((fd = open(argv[1], O_RDWR)) == -1) {
perror(argv[1]);
exit(2);
}
printf("\n수정할 학생의 학번 입력:");
while (scanf("%d", &id) == 1) {
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = (id-START_ID)*sizeof(record);
lock.l_len = sizeof(record);
if (fcntl(fd,F_SETLKW, &lock) == -1) { /* 쓰기 잠금 */
perror(argv[1]);
exit(3);
}
lseek(fd, (long) (id-START_ID)*sizeof(record), SEEK_SET);
if ((read(fd, (char *) &record, sizeof(record)) > 0) &&
(record.id != 0))
printf("이름:%s\t 학번:%d\t 점수:%d\n",
record.name, record.id, record.score);
else printf("레코드 %d 없음\n", id);
printf("새로운 점수: ");
scanf("%d", &record.score);
lseek(fd, (long) -sizeof(record), SEEK_CUR);
write(fd, (char *) &record, sizeof(record));
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock); /* 잠금 해제 */
printf("\n수정할 학생의 학번 입력:");
}
close(fd);
exit(0);
}
정리 및 느낀 점
fcntl()함수에 flock 구조체를 매개변수로 사용해 파일의 레코드를 잠금을 구현했다.
출처
창병모, 리눅스 프로그래밍, 생능출판사, 2014.