fcntl() 범위 잠금(길이에서 일부 오프셋)이 fcntl 전체 파일 잠금(EOF에서 0 오프셋)보다 느린 이유는 무엇입니까? [폐쇄]

fcntl() 범위 잠금(길이에서 일부 오프셋)이 fcntl 전체 파일 잠금(EOF에서 0 오프셋)보다 느린 이유는 무엇입니까? [폐쇄]

동시에 8개의 다른 프로세스에서 1GB 파일에 쓰려고 합니다(각 프로세스는 동시에 두 가지 다른 접근 방식에 따라 오프셋 0부터 시작하여 씁니다).

  1. 각 프로세스는 파일의 다른 영역에 쓰는 경우에도 쓰기 전에 fcntl()을 사용하여 전체 파일 잠금(오프셋 0 - EOF)을 획득합니다.
  2. 각 프로세스는 쓰기 전에 파일의 해당 영역에 대한 잠금을 획득하기 위해 fcntl()을 사용합니다.

내가 이해한 바에 따르면 두 번째 방법은 첫 번째 방법보다 시간이 덜 걸릴 것입니다. 하지만 테스트를 해보니 첫 번째 방법이 시간이 덜 걸리는 것으로 나타났습니다. 누군가 이유를 설명할 수 있나요?

기본 파일 시스템: ext4

첫 번째 방법

#define MAX_WRITE 65536

void write_file (char *path) {
        int fd;
        char buf[MAX_WRITE];
        ssize_t bytes_write;
        off64_t file_end, off;
        struct flock rl;

        fd = open64(path, O_WRONLY);
        if (fd == -1) {
                perror("open fail");
        }
        srand(time(0));
        char ch = (rand() % (33 - 122 + 1)) + 33;
        int i;
        for (i = 0; i < MAX_WRITE - 3; i += 4) {
                buf[i] = ch;
                buf[i+1] = ch;
                buf[i+2] = ch;
                buf[i+3] = ch;
        }
        buf[i+3] = '\n';
        file_end = lseek64(fd, 0, SEEK_END);
        lseek64(fd, 0, SEEK_SET);
        rl.l_type = F_WRLCK;
        rl.l_whence = SEEK_SET;
        rl.l_start = 0;
        rl.l_len = file_end;
        rl.l_pid = 0;
        for (off = 0; off < file_end; off+=bytes_write) {
                if (fcntl(fd, F_SETLKW, &rl) == -1) {
                        perror("fcntl locking failed");
                        exit(-1);
                }

                bytes_write = write(fd, buf, MAX_WRITE);
                if (bytes_write == -1) {
                        perror("Error writing file");
                        exit(-1);
                } else if (bytes_write < MAX_WRITE) {
                        printf("Partial write, only %ld no. of bytes are returned.\n",
                        bytes_write);
                }

                rl.l_type = F_UNLCK;
                if (fcntl(fd, F_SETLK, &rl) == -1) {
                        perror("fcntl locking failed");
                        exit(-1);
                }
        }
        printf("process %d Able to write %lld bytes..\n", getpid(), off);
        close(fd);
        return; 
}
int main (int argc, char **argv) {

        int fd, p_dead;
        if (argc < 3) {
                printf("Usage: %s <filename> <processes>\n", argv[0]);
                exit(-1);
        }
        char *path = argv[1];
        int p_no = atoi(argv[2]);

        /* Creating n number of processes */
        for (int i = 0; i < p_no; i++) {
                switch (fork()) {
                        case -1:
                                perror("fork failed:");
                                break;
                        case 0:
                                write_file(path);
                                exit(0);
                                break;
                        default:
                                /* Do nothing */
                                break;
                }
        }
        p_dead = 0;
        while (1) {
                if (wait(NULL) == -1) {
                        if (errno == ECHILD) {
                                printf("No child left..\n");
                                printf("Total no. of processes died : %d\n", p_dead);
                                exit(0);
                        } else {
                                perror("wait failed");
                                exit(-1);
                        }
                }
                p_dead++;
        }
        exit(0);
}

두 번째 방법

    #define MAX_WRITE 65536

void write_file (char *path) {
        int fd;
        char buf[MAX_WRITE];
        ssize_t bytes_write;
        off64_t file_end, off;
        struct flock rl;

        fd = open64(path, O_WRONLY);
        if (fd == -1) {
                perror("open fail");
        }
        srand(time(0));
        char ch = (rand() % (33 - 122 + 1)) + 33;
        int i;
        for (i = 0; i < MAX_WRITE - 3; i += 4) {
                buf[i] = ch;
                buf[i+1] = ch;
                buf[i+2] = ch;
                buf[i+3] = ch;
        }
        buf[i+3] = '\n';
        file_end = lseek64(fd, 0, SEEK_END);
        lseek64(fd, 0, SEEK_SET);
        rl.l_type = F_WRLCK;
        rl.l_whence = SEEK_CUR;
        rl.l_start = 0;
        rl.l_len = MAX_WRITE;
        rl.l_pid = 0;
        for (off = 0; off < file_end; off+=bytes_write) {
                if (fcntl(fd, F_SETLKW, &rl) == -1) {
                        perror("fcntl locking failed");
                        exit(-1);
                }
                bytes_write = write(fd, buf, MAX_WRITE);
                if (bytes_write == -1) {
                        perror("Error writing file");
                        exit(-1);
                } else if (bytes_write < MAX_WRITE) {
                        printf("Partial write, only %ld no. of bytes are returned.\n",
                        bytes_write);
                }
                rl.l_type = F_UNLCK;
                if (fcntl(fd, F_SETLK, &rl) == -1) {
                        perror("fcntl locking failed");
                        exit(-1);
                }
        }
        printf("process %d Able to write %lld bytes..\n", getpid(), off);
        close(fd);
        return;
}

int main (int argc, char **argv) {

        int fd, p_dead;
        if (argc < 3) {
                printf("Usage: %s <filename> <processes>\n", argv[0]);
                exit(-1);
        }
        char *path = argv[1];
        int p_no = atoi(argv[2]);

        /* Creating n number of processes */
        for (int i = 0; i < p_no; i++) {
                switch (fork()) {
                        case -1:
                                perror("fork failed:");
                                break;
                        case 0:
                                write_file(path);
                                exit(0);
                                break;
                        default:
                                /* Do nothing */
                                break;
                }
        }
        p_dead = 0;
        while (1) {
                if (wait(NULL) == -1) {
                        if (errno == ECHILD) {
                                printf("No child left..\n");
                                printf("Total no. of processes died : %d\n", p_dead);
                                exit(0);
                        } else {
                                perror("wait failed");
                                exit(-1);
                        }
                }
                p_dead++;
        }
        exit(0);
}

답변1

잠금 해제를 덮어써서 재사용하고 rl있으며 루프에서 재설정하지 않습니다. 두 예제 모두 첫 번째 루프 반복만 잠급니다.l_typeF_UNLCKl_type

관련 정보