错误写入同步进程的文件输出顺序?
Wrong write to file output order of synchronized processes?
我有以下问题。
我有两个正在与信号量同步的进程,我的想法是:
- 进程 1 向 txt 文件写入内容
- 进程 2 向 txt 文件写入内容
- 进程 1 向测试文件写入内容
我已经包含了演示该问题的示例代码:
// semaphore names
#define NAME1 "/s1"
#define NAME2 "/s2"
int main()
{
/* semaphores for process synchronization */
sem_t *sm1;
sm1 = sem_open( NAME1, O_CREAT, 0666, 0);
sem_t *sm2;
sm2 = sem_open(NAME2, O_CREAT, 0666, 0);
/* processes*/
int proc1;
int proc2;
/* file lock struct */
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
/* create a text file */
FILE *fp;
int fd;
fp = fopen("output.txt", "w"); // create and close the file
fclose(fp);
if((fd = open("output.txt", O_RDWR)) == -1) { // open the file again to get file descriptor
perror("open");
exit(1);
}
fp = fdopen(fd, "w");
/* first process */
if ((proc1 = fork()) < 0) {
perror("fork");
exit(2);
}
else if(proc1 == 0) {
fl.l_type = F_WRLCK; // set the lock type and pid of the forked process
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) { // lock the file before writing to it
perror("fcntl");
exit(1);
}
fprintf(fp, "proc1 - action1\n"); // write to the file
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) { // unlock the file so other processes can write to it
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc1 - action1\n");
sem_post(sm1); // let the second process run
sem_wait(sm2); // wait till the second process is done
// write one more thing the same way to the text file after the second process is done
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(fp, "proc1 - action2\n");
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc1 - action2\n");
exit(0);
}
/* second process */
if ((proc2 = fork()) < 0) {
perror("fork");
exit(2);
}
else if(proc2 == 0) {
sem_wait(sm1); // waits for proc1 to perform it's first action
// write something to the text file and let proc1 write it's second action
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(fp, "proc2 - action1\n");
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc2 - action1\n");
sem_post(sm2);
exit(0);
}
// wait for both processes to finish
waitpid(proc1, NULL, 0);
waitpid(proc2, NULL, 0);
sem_close(sm1);
sem_unlink(NAME1);
sem_close(sm2);
sem_unlink(NAME2);
return 0;
}
我已经将 fprintf 包含在标准输出行中,以便您可以看到终端中的输出是正确的:
-proc1 - action1
-proc2 - action1
-proc1 - action2
就像他们正在同步一样。但是,output.txt 文件中的输出是这样的:
-proc2 - action1
-proc1 - action1
-proc1 - action2
为什么会这样?
另外,在进程写入文件之前,我总是锁定它,这样其他进程就无法访问它,然后再解锁它。
我不确定我是否做对了,所以如果能得到任何建议,我将不胜感激!
非常感谢!
默认情况下您已经缓冲了 IO - 因此如果输出小于缓冲区大小,缓冲区实际上不会刷新到文件,直到您关闭它(否则您会在缓冲区已满时获得缓冲区的价值...通常是 8kb 左右)。另请注意,每个进程都有自己的独立缓冲区。
要修复,请在打印后和写入前刷新输出,fseek() 到 SEEK_END 以确保您位于文件末尾。
fprintf(fp, "proc1 - action1\n"); // write to the file
fflush(fp);
顺便说一句,我没有检查您的信号量代码的有效性,只是注意到您遗漏了这一重要信息。但是,一般来说,如果您使用文件锁定,则信号量是多余的...
fp = fopen("output.txt", "w");
将 截断 文件并且不同步,因此进程 #2 可能会截断文件,即使进程 #1 已经写入了一些内容。 fp = fdopen(fd, "w");
相同
此外,如果您在其他进程写入文件时保持文件打开,您就会遇到麻烦。在第二个进程完成写入后,至少你应该 SEEK
到文件的(新)末尾,否则你可以覆盖#2 进程所做的。最好在其他进程运行之前关闭文件,然后再重新打开。这还将确保刷新所有缓冲数据。
我有以下问题。
我有两个正在与信号量同步的进程,我的想法是:
- 进程 1 向 txt 文件写入内容
- 进程 2 向 txt 文件写入内容
- 进程 1 向测试文件写入内容
我已经包含了演示该问题的示例代码:
// semaphore names
#define NAME1 "/s1"
#define NAME2 "/s2"
int main()
{
/* semaphores for process synchronization */
sem_t *sm1;
sm1 = sem_open( NAME1, O_CREAT, 0666, 0);
sem_t *sm2;
sm2 = sem_open(NAME2, O_CREAT, 0666, 0);
/* processes*/
int proc1;
int proc2;
/* file lock struct */
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
/* create a text file */
FILE *fp;
int fd;
fp = fopen("output.txt", "w"); // create and close the file
fclose(fp);
if((fd = open("output.txt", O_RDWR)) == -1) { // open the file again to get file descriptor
perror("open");
exit(1);
}
fp = fdopen(fd, "w");
/* first process */
if ((proc1 = fork()) < 0) {
perror("fork");
exit(2);
}
else if(proc1 == 0) {
fl.l_type = F_WRLCK; // set the lock type and pid of the forked process
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) { // lock the file before writing to it
perror("fcntl");
exit(1);
}
fprintf(fp, "proc1 - action1\n"); // write to the file
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) { // unlock the file so other processes can write to it
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc1 - action1\n");
sem_post(sm1); // let the second process run
sem_wait(sm2); // wait till the second process is done
// write one more thing the same way to the text file after the second process is done
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(fp, "proc1 - action2\n");
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc1 - action2\n");
exit(0);
}
/* second process */
if ((proc2 = fork()) < 0) {
perror("fork");
exit(2);
}
else if(proc2 == 0) {
sem_wait(sm1); // waits for proc1 to perform it's first action
// write something to the text file and let proc1 write it's second action
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(fp, "proc2 - action1\n");
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc2 - action1\n");
sem_post(sm2);
exit(0);
}
// wait for both processes to finish
waitpid(proc1, NULL, 0);
waitpid(proc2, NULL, 0);
sem_close(sm1);
sem_unlink(NAME1);
sem_close(sm2);
sem_unlink(NAME2);
return 0;
}
我已经将 fprintf 包含在标准输出行中,以便您可以看到终端中的输出是正确的:
-proc1 - action1
-proc2 - action1
-proc1 - action2
就像他们正在同步一样。但是,output.txt 文件中的输出是这样的:
-proc2 - action1
-proc1 - action1
-proc1 - action2
为什么会这样?
另外,在进程写入文件之前,我总是锁定它,这样其他进程就无法访问它,然后再解锁它。
我不确定我是否做对了,所以如果能得到任何建议,我将不胜感激!
非常感谢!
默认情况下您已经缓冲了 IO - 因此如果输出小于缓冲区大小,缓冲区实际上不会刷新到文件,直到您关闭它(否则您会在缓冲区已满时获得缓冲区的价值...通常是 8kb 左右)。另请注意,每个进程都有自己的独立缓冲区。
要修复,请在打印后和写入前刷新输出,fseek() 到 SEEK_END 以确保您位于文件末尾。
fprintf(fp, "proc1 - action1\n"); // write to the file
fflush(fp);
顺便说一句,我没有检查您的信号量代码的有效性,只是注意到您遗漏了这一重要信息。但是,一般来说,如果您使用文件锁定,则信号量是多余的...
fp = fopen("output.txt", "w");
将 截断 文件并且不同步,因此进程 #2 可能会截断文件,即使进程 #1 已经写入了一些内容。 fp = fdopen(fd, "w");
此外,如果您在其他进程写入文件时保持文件打开,您就会遇到麻烦。在第二个进程完成写入后,至少你应该 SEEK
到文件的(新)末尾,否则你可以覆盖#2 进程所做的。最好在其他进程运行之前关闭文件,然后再重新打开。这还将确保刷新所有缓冲数据。