파일 및 레코드 잠금 목차
목표
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;
off_f l_start;
short l_whence;
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.