파일을 이용한 동기화

Juni and ING·2020년 8월 26일
0

동기화 용어

Race Condition(경쟁 상태)

둘 이상의 프로세스/스레드가 동시에 실행되고 있을 때, 타이밍 등에 의해서 의도치 않은 결과를 야기할 수 있는 상태를 의미

Critical Section(임계 영역)

둘 이상의 프로세스/스레드가 동시에 접근하면 안되는 Resource가 존재하는 코드 영역을 의미


File Lock

#include <sys/file.h>

int flock(int fd, int operation);

인자

fd

파일 디스크립터

operation

Lock 설정

  • LOCK_SH
    공유 Lock 시도

  • LOCK_EX
    상호배제 Lock 시도

  • LOCK_UN
    점유Lock 해제

  • LOCK_NB
    Non-block(Lock될 때까지 대기하지 않음)

반환값

성공 시

0

실패 시

-1(LOCK_NB가 Set되어 있을 때만 실패반환이 발생할 수 있음)


Example

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/file.h>



#define TARGET_FILE "file"
#define isNonBlock(x) ( strcmp(x, "nb") == 0)
#define isSameStr(x, y) ( strcmp(x,y) == 0 )
#define isFdOpened(x) ( (fd >= 0) && (fd != fileno(stdin)) && (fd != fileno(stdout)) && (fd != fileno(stderr)) )

static void write_file(bool isNonBlock)
{
    int fd = -1, operation;
    char *str = "Hello, World~!\n";

    fd = open(TARGET_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644);
    if(fd < 0){
        perror("open() FAIL\n");
        goto EXCEPTION;
    }

    (isNonBlock) ? (operation = LOCK_EX | LOCK_NB) 
                : (operation = LOCK_EX);

    if(flock(fd, operation) < 0){
        fprintf(stderr, "flock(%d) FAIL : %s\n", operation, strerror(errno));
        goto EXCEPTION;
    }

    printf("Press enter!\n");
    getc(stdin);    

    write(fd, str, strlen(str));

    if(flock(fd, LOCK_UN) < 0){
        perror("<<WARNING>> flock(LOCK_UN) FAIL\n");
    }

    close(fd);
    return;

EXCEPTION:
    if(isFdOpened(fd)) close(fd);
    return;
}

static void dump_file(bool isNonBlock)
{
    #define MAX_STR_LEN 128
    int fd = -1, operation, maxStrIdx = MAX_STR_LEN - 1, cnt;
    char buf[MAX_STR_LEN];

    fd = open(TARGET_FILE, O_RDONLY | O_CREAT, 0644);
    if(fd < 0){
        perror("open() FAIL\n"); 
        goto EXCEPTION;
    }

    (isNonBlock) ? (operation = LOCK_SH | LOCK_NB)
                : (operation = LOCK_SH);
    
    if(flock(fd, operation) < 0){
        fprintf(stderr, "flock(%d) FAIL : %s\n", operation, strerror(errno));
        goto EXCEPTION;
    }

    printf("Press enter!\n");
    getc(stdin);

    cnt = read(fd, buf, maxStrIdx);
    buf[cnt] = 0;

    if(flock(fd, LOCK_UN) < 0){
        perror("flock(LOCK_UN) FAIL\n");
        goto EXCEPTION;
    }

    puts(buf);

    close(fd);
    return;

EXCEPTION:
    if(isFdOpened(fd)) close(fd);
    return;
}

static void diplay_usage(const char * const binName)
{
    printf("Usage: %s w|r [nb]\n", binName);
}

int main(int argc, char **argv)
{
    if( (argc < 2) || (3 < argc) ){
        diplay_usage(argv[0]);
        goto EXCEPTION;
    }

    bool nb = false;

    if(argc == 3) nb = isNonBlock(argv[2]);

    if(isSameStr(argv[1], "w")){
        write_file(nb);
    }
    else if(isSameStr(argv[1], "r")){
        dump_file(nb);
    }
    else {
        diplay_usage(argv[0]);
        goto EXCEPTION;
    }

    return 0;

EXCEPTION:
    return -1;
}
profile
인기는 없지만 그래도 임베디드를 사랑하는 한 개발자

0개의 댓글