2016-04-25 93 views
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 

爲什麼會發生這種情況?

此外,在進程寫入文件之前,我總是鎖定它,以便其他進程無法訪問它並再次解鎖。

我不確定我是否做得對,所以我會很感激我能得到的任何建議!

非常感謝!

回答

1

默認情況下,您已經緩衝了IO - 因此,如果緩衝區的輸出小於緩衝區大小,那麼緩衝區實際上並不會被刷新到該文件,直到您關閉它爲止(否則您會在緩衝區已滿時獲得緩衝區的值。經常8kb左右)。還要注意,每個進程都有自己獨立的緩衝區。

要修復,請在打印完成後刷新輸出,並在寫入之前將fseek()更改爲SEEK_END以確保您位於文件末尾。

fprintf(fp, "proc1 - action1\n"); // write to the file 
fflush(fp); 

順便說一句,我沒有檢查你的信號量代碼的有效性,只是注意到你錯過了這個重要的信息。但一般情況下,如果你使用的文件鎖定,信號量是多餘的...

+0

另請參閱https://www.quora.com/In-C-what-does-buffering-IO-or-buffered-IO-mean – JimmyB

+0

我編輯瞭如下代碼:fseek(fp,0,SEEK_END) ; fprintf(fp,「proc1 - action1 \ n」); fflush(fp);它似乎在工作。我做對了嗎?非常感謝您的信息!請問,文件鎖定怎麼辦?我是否正確地使用每個寫入操作來鎖定和解鎖文件?我正在考慮是否有更優雅的方式來做這件事,因爲當我可以說,10在每個進程中寫這樣的動作時,代碼很快就變得亂七八糟。 – Daeto

1

fp = fopen("output.txt", "w");截斷文件和不同步,所以進程#2可能會截斷文件,即使進程#1已經寫了一些東西。 fp = fdopen(fd, "w");

另外,如果在其他進程寫入文件時保持打開文件,那麼您將面臨麻煩。在第二個過程完成其寫入之後,至少應將SEEK添加到文件的(新)結尾,否則您可能會覆蓋#2所執行的過程。在其他進程運行之前更好地關閉文件,然後重新打開。這也將確保所有緩衝數據都被刷新。

相關問題