2012. 7. 13. 16:30

레코드 잠금

fcntl() 파일을 제어한다.

int fcntl(int fd,int cmd,struct flock *lock)

struct flock의 l_type멤버

F_RDLCK 읽기잠금을 설정한다.
F_WRLCK 쓰기잠금을 설정한다. 다른 프로세스의 모든 잠금을 막아 다른 프로세스가 파일을 읽고,쓰지 못함
F_UNLCK 잠금을 해제한다.

struct flock의 l_whence멤버, l_start, l_len

SEEK_SET
SEEK_CUR
SEEK_END

------------------------------------------------------------------------------------------------------
a.out 파일을 만들고 잠금

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

main(int argc, char *argv[])
{
    int fd;
    struct flock filelock;

    /* argv[1]의 내용이 “r”이면 F_RDLCK를, 아니면 F_WRLCK를 filelock.l_type에 저장 */
    filelock.l_type = (!strcmp(argv[1],"r"))?F_RDLCK:F_WRLCK;
    /* 파일 전체를 영역으로 */
    filelock.l_whence = SEEK_SET;
    filelock.l_start = 0;
    filelock.l_len = 0;

    /* argv[2] 파일을 여는데 없으면 생성 */
    fd = open(argv[2], O_RDWR | O_CREAT, 0666);

    /* fd 파일 즉, argv[2]에 대해 filelock 형태로 레코드 잠금을 설정 */
    if(fcntl(fd, F_SETLK, &filelock) == -1) {
       perror("fcntl failed");
       exit(1);
    }
    printf("locked %s\n", argv[2]);
    sleep(30);
    printf("unlocked %s\n", argv[2]);
    exit(0);
}


b.out
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

main(int argc, char *argv[])
{
    int fd;
    struct flock filelock;

    filelock.l_type = (!strcmp(argv[1],"r"))?F_RDLCK:F_WRLCK;
    /* 파일 전체를 영역으로 */
    filelock.l_whence = SEEK_SET;
    filelock.l_start = 0;
    filelock.l_len = 0;

    fd = open(argv[2], O_RDWR);   /* agrv[2] 파일 열기 */

    /* fd 파일에 대해 filelock 형태로 레코드 잠금을 설정. 설정에 실패하면 -1을 반환 */
    if(fcntl(fd, F_SETLK, &filelock) == -1) {
       perror("fcntl failed");
       exit(1);
    }
    /* 레코드 잠금에 성공하면 실행 */
    printf("success\n");
    exit(0);
}

[localhost@local]#a.out r file&
locked file
[localhost@local]#b.out r file
success --> 파일 잠금 성공
[localhost@local]#b.out w file 쓰기 시도
잠금시도
fcntl failed : Resource temporaily unavilable
unlocked file
[localhost@local]#a.out w file&
locked file
[localhost@local]#b.out r file 쓰기 시도
잠금시도
fcntl failed : Resource temporaily unavilable
[localhost@local]#b.out w file 쓰기 시도
잠금시도
fcntl failed : Resource temporaily unavilable
unlocked file


--------------------------------------------------------------------------------------------------------
fcntl함수에서 레코드 잠금을 설정하는 cmd값은 F_SETLK와 F_SETLKW 두 가지가 있는데

F_SETLK는 레코드가 다른 프로세스에 의해 이미 잠겨 실패했을 때 실패를 반환하는 반면

F_SETLKW는 성공할때 까지 기다린다

부모프로세스에 의해 쓰기 잠금된 파일에 대해 자식 프로세스가 잠금을 요청했으나 실패하여 레코드 잠금이

해제될 때 까지 기다린다.


#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>

main(int argc, char *argv[])
{
    int fd;
    struct flock filelock;

    filelock.l_type = F_WRLCK;   /* 쓰기 잠금 */
    filelock.l_whence = SEEK_SET;   /* 파일의 시작을 기준으로 */
    filelock.l_start = 0;   /* 기준의 처음부터 */

    fd = open(argv[1], O_RDWR);   /* agrv[1] 파일 열기 */

    /* fork에 의해 자식 프로세스를 생성 */
    switch(fork()) {
       /* fork 호출에 실패하면 */
       case -1:
          perror("fork failed");
          exit(1);
       /* 자식 프로세스는 */
       case 0:
          filelock.l_len = 5;   /* 5바이트 크기에 대해 */
          /* fd 파일에 대해 레코드 잠금을 설정.
            이미 레코드 잠금이 설정되어 있으면 해제될 때까지 기다림 */
          if(fcntl(fd, F_SETLKW, &filelock) == -1) {
             perror("fcntl failed");
             exit(1);
          }
          printf("child process: locked\n");
          sleep(3);
          /* 레코드 잠금을 해제 */
          filelock.l_type = F_UNLCK;
          if(fcntl(fd, F_SETLK, &filelock) == -1) {
             perror("fcntl failed");
             exit(1);
          }
          printf("child process: unlocked\n");
          break;
       /* 부모 프로세스는 */
       default:
          filelock.l_len = 10;   /* 10바이트 크기에 대해 */
          /* fd 파일에 대해 레코드 잠금을 설정 */
          if(fcntl(fd, F_SETLKW, &filelock) == -1) {
             perror("fcntl failed");
             exit(1);
          }
          printf("parent process: locked\n");
          sleep(3);
          /* 레코드 잠금을 해제 */
          filelock.l_type = F_UNLCK;
          if(fcntl(fd, F_SETLK, &filelock) == -1) {
             perror("fcntl failed");
             exit(1);
          }
          printf("parent process: unlocked\n");
          /* 자식 프로세스가 종료될 때까지 기다림 */
          wait(NULL);
    }
    exit(0);
}

[localhost@local]# a.out file
parent process : locked
parend process : unlocked
child process : locked
child process : unlocked

Posted by 몰라욧