Re: [問題] 兩個process寫入同一個檔案的疑問

作者: hth9494 (hth9494)   2022-07-11 12:25:20
※ 引述《hth9494 (掰掰惹 仙度瑞拉)》之銘言:
: 開發平台(Platform): (Ex: Win10, Linux, ...)
: Linux kali 5.18.0-kali2-amd64 #1 SMP PREEMPT_DYNAMIC Debian 5.18.5-1kali1
: (2022-06-20) x86_64 GNU/Linux
: 編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
: gcc (Debian 11.3.0-3) 11.3.0
: 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
: 問題(Question):
: 我有兩個process開啟同一個file,且兩個process同時向file寫入字串
: 一個寫入"a",一個寫入"b",各自重複寫入200次
: 每一次寫入,兩個process就會printf出當前ftell的值
: 問題:
: 我期待看到file中ab會交替出現
: 但並沒有,而是a全部出現完才換b,或者b出現完才換a
: 不過從console上印出的ftell值卻又顯示
: 這兩個process顯然是交替執行著,並不是一個執行完才換另一個
: 既然如此,為什麼file的內容不是交替的顯示a和b呢
: 請問要如何做才能看到ab交替的結果
: 謝謝
: 餵入的資料(Input):
: 預期的正確結果(Expected Output):
: file中a和b交替顯示
: 錯誤結果(Wrong Output):
: 200個a全部顯示完才換b,或者200個b顯示完才換a
: 程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔)
: #include <stdio.h>
: #include <stdlib.h>
: #include <string.h>
: int main()
: {
: FILE *pfile;
: int id = fork();
: if (id == 0) {
: char *str = "a";
: pfile = fopen("testfile", "a");
: if (pfile) {
: int i;
: for (i = 0; i < 200; i++) {
: printf("a = %d\n", ftell(pfile));
: fwrite(str, 1, strlen(str), pfile);
: }
: }
: }
: else if (id > 0) {
: printf("id = %d\n", id);
: char *str = "b";
: pfile = fopen("testfile", "a");
: if (pfile) {
: int i;
: for (i=0;i<200;i++) {
: printf("b = %d\n", ftell(pfile));
: fwrite(str, 1, strlen(str), pfile);
: }
: }
: }
: fclose(pfile);
: return 0;
: }
: 補充說明(Supplement):
抱歉,我原先的問題描述不準確
我原文所謂的交替是指,我預期a和b會有不規則穿插的效果
像是aaabbaaaaaabbbbbabababaaa
而非abababababababababababab
因為本來只是想練習fork()和感受一下race condition的效果
結果因為用fwrite導致檔案內容不如預期才上來發問
但看了板友的推文,我就也想練習一下要怎麼做才能abababababababab
因為目前還不會IPC或condition variable之類的觀念
所以只想到笨方法
現在變成有兩個檔案,原先的testfile和一個新的check
當process a寫入testfile後,會在check寫下一個屬於a的標記,表示已經寫入testfile
當process b寫入testfile後,亦然
process a 在寫入檔案前
先不斷去判斷check,看看b是否有寫入標記了
如果確認b已寫入,才會寫入testfile
process b 也做一樣的動作
我執行後這樣就能達成ababab的效果
前提要先建立check並且給一個初始的標記
我大概知道這樣會有一些問題,像是a跟b要不停去檢查check,而非等待通知再執行
導致浪費CPU資源等等
但我這個作法除了這個問題外,是否已能保證執行結果一定是abababab呢
是否要給check加鎖什麼的,否則在check上也會發生race condition的問題
導致結果不是abababab?
謝謝各位
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *pfile = NULL;
int id = fork();
if (id == 0) {
// process a, keep writting a
char *str = "a";
pfile = fopen("testfile", "a");
if (pfile) {
int fd = fileno(pfile);
int i;
for (i = 0; i < 200; i++) {
// keep checking until b is written
char c = 0;
while (c != 'b') {
FILE *pcheck = fopen("check", "r");
int fdcheck = fileno(pcheck);
read(fdcheck, &c, 1);
fclose(pcheck);
}
// write a
printf("a = %d\n", ftell(pfile));
write(fd, str, 1);
// update check
FILE *pcheck = fopen("check", "w");
int fdcheck = fileno(pcheck);
write(fdcheck, str, 1);
fclose(pcheck);
}
}
}
else if (id > 0) {
// process b , keep writting b
char *str = "b";
pfile = fopen("testfile", "a");
if (pfile) {
int fd = fileno(pfile);
int i;
for (i=0;i<200;i++) {
// keep checking until a is written
char c = 0;
while (c != 'a') {
FILE *pcheck = fopen("check", "r");
int fdcheck = fileno(pcheck);
read(fdcheck, &c, 1);
fclose(pcheck);
}
// write b
printf("b = %d\n", ftell(pfile));
write(fd, str, 1);
// update check
FILE *pcheck = fopen("check", "w");
int fdcheck = fileno(pcheck);
write(fdcheck, str, 1);
fclose(pcheck);
}
}
}
if (pfile)
fclose(pfile);
return 0;
}
作者: qscgy4 (有點厲害)   2022-07-11 13:45:00
如果只是想看 abbababbbaa 那你直接printf或cout都能看如果想要在檔案看到,那就多寫一個thread來接收那個thread就按接收順序寫入這樣應該最簡單
作者: wulouise (在線上!=在電腦前)   2022-07-12 07:50:00
你的實作在兩個producer的時候沒事,多個的時候不好處理
作者: longlongint (華哥爾)   2022-07-12 14:08:00
有試過 sync write 嗎
作者: WPC001 (好悶, 迷惘~~)   2022-07-15 21:23:00
要不規則穿插... 除非寫入內容很長... 或是每寫一個byte就主動睡下去...基本上你有fclose... 應該是已經被flush了,多加個sleep吧
作者: choosin (秋心)   2022-07-19 11:49:00
file本身就是IPC的一種 要abab更簡單 開檔檢查結尾寫回就好 依照你本來想寫200a跟200b 那最後如果沒有200a+200b那也可以看到race condition的發生

Links booklink

Contact Us: admin [ a t ] ucptt.com