我试图同时从 8 个不同的进程写入 1 GB 文件(每个进程将从第 0 个偏移量开始写入直到 EOF);同时遵循两种不同的方法。
- 在写入之前,每个进程都将使用 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