동시에 8개의 다른 프로세스에서 1GB 파일에 쓰려고 합니다(각 프로세스는 동시에 두 가지 다른 접근 방식에 따라 오프셋 0부터 시작하여 씁니다).
- 각 프로세스는 파일의 다른 영역에 쓰는 경우에도 쓰기 전에 fcntl()을 사용하여 전체 파일 잠금(오프셋 0 - EOF)을 획득합니다.
- 각 프로세스는 쓰기 전에 파일의 해당 영역에 대한 잠금을 획득하기 위해 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_type
F_UNLCK
l_type