|     1.實驗目的     通(tong)過編(bian)寫文(wen)件讀寫及上(shang)鎖(suo)的程序,進一步(bu)熟(shu)悉Linux中文(wen)件I/O相關的應用開發,并且熟(shu)練掌握open()、read()、write()、fcntl()等函數(shu)的使用。     2.實驗(yan)內容     在Linux中FIFO是一(yi)種進程間的(de)管道通(tong)信機制(zhi),Linux支持完(wan)整的(de)FIFO通(tong)信機制(zhi)。     本(ben)實驗內容比(bi)較(jiao)有趣,我們通(tong)過使用文件操作,仿真FIFO(先(xian)進先(xian)出)結(jie)構及生產者—消費(fei)者運行模型(xing)。     本實驗中需要打開(kai)兩個(ge)虛(xu)擬終端,分別運行生產(chan)者(zhe)程(cheng)序(xu)(producer)和消(xiao)費者(zhe)程(cheng)序(xu)(customer),此(ci)時兩個(ge)進程(cheng)同(tong)時對同(tong)一個(ge)文件(jian)(jian)進行讀寫操作。因為這(zhe)個(ge)文件(jian)(jian)是(shi)臨界資(zi)源(yuan),所(suo)以可以使用文件(jian)(jian)鎖機制(zhi)來保(bao)證(zheng)兩個(ge)進程(cheng)對文件(jian)(jian)的訪問(wen)都(dou)是(shi)原子操作。     先(xian)啟動生(sheng)(sheng)產(chan)者(zhe)進程(cheng),它負責創建(jian)仿真FIFO結構的文(wen)件(jian)(其實是(shi)一個普通文(wen)件(jian))并投入生(sheng)(sheng)產(chan),就是(shi)按(an)照(zhao)給定(ding)的時(shi)間間隔,向FIFO文(wen)件(jian)寫入自動生(sheng)(sheng)成的字(zi)(zi)符(在(zai)程(cheng)序(xu)中用(yong)宏定(ding)義選擇使用(yong)數字(zi)(zi)還是(shi)使用(yong)英文(wen)字(zi)(zi)符),生(sheng)(sheng)產(chan)周期(qi)及要(yao)生(sheng)(sheng)產(chan)的資(zi)源(yuan)數通過參數傳遞(di)給進程(cheng)(默認(ren)生(sheng)(sheng)產(chan)周期(qi)為(wei)1s,要(yao)生(sheng)(sheng)產(chan)的資(zi)源(yuan)總數為(wei)10個字(zi)(zi)符,顯然默認(ren)生(sheng)(sheng)產(chan)總時(shi)間為(wei)10s)。     后啟動的(de)消(xiao)費(fei)者進(jin)程按照給定的(de)數(shu)目進(jin)行消(xiao)費(fei),首先從(cong)(cong)文(wen)件(jian)中讀(du)取相應(ying)數(shu)目的(de)字(zi)符并(bing)在屏(ping)幕上顯示,然后從(cong)(cong)文(wen)件(jian)中刪(shan)除剛才消(xiao)費(fei)過(guo)的(de)數(shu)據。為(wei)了仿真FIFO結構(gou),此時需要使用兩次(ci)(ci)復制(zhi)來實現文(wen)件(jian)內容(rong)的(de)偏移(yi)。每次(ci)(ci)消(xiao)費(fei)的(de)資源(yuan)數(shu)通過(guo)參數(shu)傳遞給進(jin)程,默認值為(wei)10個(ge)字(zi)符。     3.實驗步驟     (1)畫出實驗流(liu)程圖(tu)。     本實驗的兩個程(cheng)序的流(liu)程(cheng)圖如圖2.5所示(shi)。  圖(tu)2.5  文件讀寫及上鎖實驗流程圖(tu)
     (2)編(bian)寫代碼(ma)。     本實驗(yan)中的(de)生產者(zhe)程序(xu)的(de)源代碼如下所示(shi),其中用(yong)到(dao)的(de)lock_set()函數可參見后(hou)面章節。     /* producer.c */#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <fcntl.h>
 #include "mylock.h"
 
 #define MAXLEN			10		/* 緩沖區大小大值 */
 #define ALPHABET		1			/* 表示使用英文字符 */
 #define ALPHABET_START		'a'	/* 頭一個字符,可以用 'A' */
 #define COUNT_OF_ALPHABET	26		/* 字母字符的個數 */
 
 #define DIGIT			2			/* 表示使用數字字符 */
 #define DIGIT_START		'0'		/* 頭一個字符 */
 #define COUNT_OF_DIGIT		10	/* 數字字符的個數 */
 
 #define SIGN_TYPE	ALPHABET			/* 本實例選用英文字符 */
 const char *fifo_file = "./myfifo";/* 仿真FIFO文件名 */
 char buff[MAXLEN];				/* 緩沖區 */
 
 /* 功能:生產一個字符并寫入到仿真FIFO文件中 */
 int product(void)
 {
 int fd;
 unsigned int sign_type, sign_start, sign_count, size;
 static unsigned int counter = 0;
 
 /* 打開仿真FIFO文件 */
 if ((fd = open(fifo_file, O_CREAT|O_RDWR|O_APPEND, 0644)) < 0)
 {
 printf("Open fifo file error\n");
 exit(1);
 }
 
 sign_type =  SIGN_TYPE;
 switch(sign_type)
 {
 case ALPHABET:/* 英文字符 */
 {
 sign_start = ALPHABET_START;
 sign_count = COUNT_OF_ALPHABET;
 }
 break;
 
 case DIGIT:/* 數字字符 */
 {
 sign_start = DIGIT_START;
 sign_count = COUNT_OF_DIGIT;
 }
 break;
 
 default:
 {
 return -1;
 }
 }/*end of switch*/
 
 sprintf(buff, "%c", (sign_start + counter));
 counter = (counter + 1) % sign_count;
 
 lock_set(fd, F_WRLCK); /* 上寫鎖 */
 if ((size = write(fd, buff, strlen(buff))) < 0)
 {
 printf("Producer: write error\n");
 return -1;
 }
 lock_set(fd, F_UNLCK); /* 解鎖 */
 
 close(fd);
 return 0;
 }
 
 int main(int argc ,char *argv[])
 {
 int time_step = 1; 	/* 生產周期 */
 int time_life = 10; 	/* 需要生產的資源總數 */
 
 if (argc > 1)
 {/* 第一個參數表示生產周期 */
 sscanf(argv[1], "%d", &time_step);
 }
 if (argc > 2)
 {/* 第二個參數表示需要生產的資源數 */
 sscanf(argv[2], "%d", &time_life);
 }
 while (time_life--)
 {
 if (product() < 0)
 {
 break;
 }
 sleep(time_step);
 }
 
 exit(EXIT_SUCCESS);
 }
     本(ben)實驗中的消費者程序(xu)的源代碼如下所示:     /* customer.c */#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <fcntl.h>
 
 #define MAX_FILE_SIZE		100 * 1024 * 1024 /* 100M */
 
 const char *fifo_file = "./myfifo";		/* 仿真FIFO文件名 */
 const char *tmp_file = "./tmp";			/* 臨時文件名 */
 
 /* 資源消費函數 */
 int customing(const char *myfifo, int need)
 {
 int fd;
 char buff;
 int counter = 0;
 
 if ((fd = open(myfifo, O_RDONLY)) < 0)
 {
 printf("Function customing error\n");
 return -1;
 }
 
 printf("Enjoy:");
 lseek(fd, SEEK_SET, 0);
 while (counter < need)
 {
 while ((read(fd, &buff, 1) == 1) && (counter < need))
 {
 fputc(buff, stdout); /* 消費就是在屏幕上簡單的顯示 */
 counter++;
 }
 }
 fputs("\n", stdout);
 close(fd);
 return 0;
 }
 
 /* 功能:從sour_file文件的offset偏移處開始,
 將count字節數據復制到dest_file文件 */
 int myfilecopy(const char *sour_file,
 const char *dest_file, int offset, int count, int copy_mode)
 {
 int in_file, out_file;
 int counter = 0;
 char buff_unit;
 
 if ((in_file = open(sour_file, O_RDONLY|O_NONBLOCK)) < 0)
 {
 printf("Function myfilecopy error in source file\n");
 return -1;
 }
 
 if ((out_file = open(dest_file, O_CREAT|O_RDWR|O_TRUNC|O_NONBLOCK, 0644)) < 0)
 {
 printf("Function myfilecopy error in destination file:");
 return -1;
 }
 
 lseek(in_file, offset, SEEK_SET);
 while ((read(in_file, &buff_unit, 1) == 1) && (counter < count))
 {
 write(out_file, &buff_unit, 1);
 counter++;
 }
 
 close(in_file);
 close(out_file);
 return 0;
 }
 
 /* 功能:實現FIFO消費者 */
 int custom(int need)
 {
 int fd;
 
 /* 對資源進行消費,need表示該消費的資源數目 */
 customing(fifo_file, need);
 
 if ((fd = open(fifo_file, O_RDWR)) < 0)
 {
 printf("Function myfilecopy error in source_file:");
 return -1;
 }
 
 /* 為了模擬FIFO結構,對整個文件內容進行平行移動 */
 lock_set(fd, F_WRLCK);
 myfilecopy(fifo_file, tmp_file, need, MAX_FILE_SIZE, 0);
 myfilecopy(tmp_file, fifo_file, 0, MAX_FILE_SIZE, 0);
 lock_set(fd, F_UNLCK);
 unlink(tmp_file);
 close(fd);
 return 0;
 }
 
 int main(int argc ,char *argv[])
 {
 int customer_capacity = 10;
 
 if (argc > 1) /* 第一個參數指定需要消費的資源數目,默認值為10 */
 {
 sscanf(argv[1], "%d", &customer_capacity);
 }
 if (customer_capacity > 0)
 {
 custom(customer_capacity);
 }
 exit(EXIT_SUCCESS);
 }
     (3)先在宿(su)主機上(shang)編譯該程序,如下所示:     $ make clean; make     (4)在確保沒有編譯錯誤后,交叉編譯該程序,此時需(xu)要修改Makefile中的變量。     CC = arm-linux-gcc /* 修改Makefile中的編譯器 */$ make clean; make
     (5)將生成的(de)可執行(xing)程序下載到目標板(ban)上運(yun)行(xing)。     4.實(shi)驗結(jie)果     此實驗(yan)在目標板上的運行(xing)結(jie)果如下所(suo)示(shi)。實驗(yan)結(jie)果會和這(zhe)兩個(ge)進程(cheng)(cheng)運行(xing)的具(ju)體過程(cheng)(cheng)相關,希望讀者能具(ju)體分析每種(zhong)情(qing)況(kuang),下面列出其中(zhong)一種(zhong)情(qing)況(kuang)。     終端一:     $ ./producer 1 20 /* 生產周期為1s,需要生產的資源總數為20個 */Write lock set by 21867
 Release lock by 21867
 Write lock set by 21867
 Release lock by 21867
 …
     終(zhong)端二(er):     $ ./customer 5 			/* 需要消費的資源數為5個 */Enjoy:abcde				/* 對資源進行消費,即打印到屏幕上 */
 Write lock set by 21872  	/* 為了仿真FIFO結構,進行兩次復制 */
     Release lock by 21872
     在(zai)兩個(ge)進(jin)程結束后,仿(fang)真FIFO文件的(de)內容如下:     $ cat myfifofghijklmnopqr   /* a到(dao)e的5個字符(fu)已經被消費,就剩下后面15個字符(fu) */
     本文選自華清遠見嵌入式培訓教材《從實踐中學嵌入式Linux應用程序開發》    熱點(dian)鏈(lian)接(jie):     
         1、linux 文件鎖的實現及其應用2、嵌入式Linux串口應用編程之串口讀寫
 3、Linux文件系統之虛擬文件系統
 4、標準I/O操作函數詳解
 5、標準I/O操作的緩沖存儲類型
 
 更多新聞>>  |