错误地写入同步进程的文件输出顺序?
问题描述:
我有以下问题。错误地写入同步进程的文件输出顺序?
我正在与信号灯同步的两个过程和思路是这样的:
- 过程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所执行的过程。在其他进程运行之前更好地关闭文件,然后重新打开。这也将确保所有缓冲数据都被刷新。
另请参阅https://www.quora.com/In-C-what-does-buffering-IO-or-buffered-IO-mean – JimmyB
我编辑了如下代码:fseek(fp,0,SEEK_END) ; fprintf(fp,“proc1 - action1 \ n”); fflush(fp);它似乎在工作。我做对了吗?非常感谢您的信息!请问,文件锁定怎么办?我是否正确地使用每个写入操作来锁定和解锁文件?我正在考虑是否有更优雅的方式来做这件事,因为当我可以说,10在每个进程中写这样的动作时,代码很快就变得乱七八糟。 – Daeto