我們先假設有一個檔案叫Resource.TXT,它會被兩個程序 (Process 0, Process 1)去存取。可是,如果當這兩個行程,同時要寫資料到Resource.TXT這個檔案,那麼一定會有問題,會發生Race Condition (競走現象)。為了要解決這樣的問題,我們可以先用一個很笨的方法:
1. 當Process 0要去存取Resource.TXT時,先建立一個檔案鎖 (Lock File);
2. 而Process 1要去存取Resource.TXT時,先去判斷檔案鎖是否存在,如果存在,就表示有其它的行程正在存取當中,所以程序先行等待;
3. 當Process 0存取結束時,就把檔案鎖給刪除;
4. 而Process 1再去確認檔案鎖是否存在,若不存在,表示沒有行程在存取,換Process 1自行存取。
很簡單吧!其實,這種避免許多行程去存取某一個資源的競走現象,在作業系統的觀念中還蠻重要的;在更深入的Linux Kernel Space也會用到。
所以,基於以上4點,用幾行簡單的程式碼,具體實踐。
#include "proc.h" #define SECONDS 30 int main(void) { FILE *fp = (FILE *)NULL; char *pStr0 = (char *)NULL; creat(LOCK_FILE, S_IROTH); fp = fopen(RESOURCE_FILE, "r"); if (fp == (FILE *)NULL) { fprintf(stderr, "Open the Resource File: %s ERROR!! \n", RESOURCE_FILE); exit(EXIT_FAILURE); } pStr0 = (char *)calloc(sizeof(char), 16); fread((void *)pStr0, sizeof(char), 16, fp); fprintf(stdout, "pStr0: %s", pStr0); fprintf(stdout, "Waiting for %d seconds.... \n", SECONDS); sleep(SECONDS); fprintf(stdout, "Done!! \n"); free((void *)pStr0); fclose(fp); remove(LOCK_FILE); return 0; }首先,我們在Process 0程式一開始執行時,就先用creat()函式來建立一個檔案鎖 (/var/tmp/Resource.lck),
接著,我們開始用fopen(), fread(), fprintf()等函式來讀取Resource.TXT檔案,並且將之顯示出來;
再來,為了讓Process 1有時間去存取和驗證,用sleep()函式讓程序等待30秒之後再結束,
最後,在程序結束前,要記得把檔案鎖給刪除。
再看Process 1的程式碼:
#include "proc.h" #define SECONDS 3 int main(void) { struct stat stTemp; int fd = 1, nRet = 1; FILE *fp = (FILE *)NULL; char *pStr1 = (char *)NULL; bzero((void *)&stTemp, sizeof(struct stat)); do { fd = open(LOCK_FILE, O_RDONLY); nRet = fstat(fd, &stTemp); fprintf(stdout, "Warning: The file was LOCKed!! Please wait.... \n"); sleep(SECONDS); } while (nRet == 0); close(fd); pStr1 = (char *)malloc(sizeof(char) * 16); fp = fopen(RESOURCE_FILE, "r"); if (fp == (FILE *)NULL){ fprintf(stderr, "Open the Resource File: %s ERROR!! \n", RESOURCE_FILE); exit(EXIT_FAILURE); } pStr1 = (char *)malloc(sizeof(char) * 16); fread((void *)pStr1, sizeof(char), 16, fp); fprintf(stdout, "pStr1: %s", pStr1); fclose(fp); free((void *)pStr1); return 0; }程序一開始就先判斷檔案鎖是否存在,這裡判斷的方法是,用低階I/O的open()函式開啟檔案之後,用fstat()函式去判斷檔案鎖是否存在;
因為fstat()函式執行成功會回傳0,所以在while-loop當中,fstat()一直回傳0就表示檔案鎖存在,我們就顯示一小段警告訊息,並且用sleep()函式等待3秒鐘,直到檔案鎖被Process 0給移除之後,才會跳出迴圈。
跳出回圈之後,就可以讀取Resource.TXT了,把內容讀出來。
再把其它的相關檔案程式碼補齊:
proc.h:
#ifndef __PROC_H__ #define __PROC_H__ #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <stdlib.h> #define RESOURCE_FILE "./Resource.TXT" #define LOCK_FILE "/var/tmp/Resource.lck" #endifMakefile:
GCC := gcc CFLAGS := -o OBJS := proc0.o proc1.o EXEC := proc0.out proc1.out RM := rm -rf .PHONY: all all: $(EXEC) $(EXEC): $(OBJS) @-$(GCC) $(CFLAGS) proc0.out proc0.o @-$(GCC) $(CFLAGS) proc1.out proc1.o $(OBJS): %.o: %.c @-$(GCC) -c $< $(CFLAGS) $@ .PHONY: clean cleanall install print tar dist TAGS check test clean: @-$(RM) *.o cleanall: clean @-$(RM) $(EXEC) install: print: tar: dist: TAGS: check: test:Resource.TXT:
Hello!! World!!執行結果如下圖所示:
這樣的作法,相當的笨拙,且不夠聰明。好在Linux的User Space下還提供了另外一種更好的方式─fcntl()函式 (File Control);這一篇文章只不過是個引言,接下就會記錄如何使用fcntl()函式來避免競走現象。
沒有留言:
張貼留言