当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]通过编写文件读写及上锁的程序,进一步熟悉Linux中文件I/O相关的应用开发,并且熟练掌握open()、read()、write()、fcntl()等函数的使用。

6.6实验内容6.6.1文件读写及上锁1.实验目的

通过编写文件读写及上锁的程序,进一步熟悉Linux中文件I/O相关的应用开发,并且熟练掌握open()、read()、write()、fcntl()等函数的使用。

2.实验内容

在Linux中FIFO是一种进程之间的管道通信机制。Linux支持完整的FIFO通信机制。

本实验内容比较有趣,通过使用文件操作,仿真FIFO(先进先出)结构以及生产者-消费者运行模型。

本实验中需要打开两个虚拟终端,分别运行生产者程序(producer)和消费者程序(customer)。此时两个进程同时对同一个文件进行读写操作。因为这个文件是临界资源,所以可以使用文件锁机制来保证两个进程对文件的访问都是原子操作。

先启动生产者进程,它负责创建仿真FIFO结构的文件(其实是一个普通文件)并投入生产,就是按照给定的时间间隔,向FIFO文件写入自动生成的字符(在程序中用宏定义选择使用数字还是使用英文字符),生产周期以及要生产的资源数通过参数传递给进程(默认生产周期为1s,要生产的资源数为10个字符)。

后启动的消费者进程按照给定的数目进行消费,首先从文件中读取相应数目的字符并在屏幕上显示,然后从文件中删除刚才消费过的数据。为了仿真FIFO结构,此时需要使用两次复制来实现文件内容的偏移。每次消费的资源数通过参数传递给进程,默认值为10个字符。

3.实验步骤

(1)画出实验流程图。

本实验的两个程序的流程图如图6.4所示。

图6.4节流程图

(2)编写代码。

本实验中的生产者程序的源代码如下所示,其中用到的lock_set()函数可参见第6.3.2节。

/*producer.c*/

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#include<string.h>

#include<fcntl.h>

#include"mylock.h"

#defineMAXLEN10/*缓冲区大小最大值*/

#defineALPHABET1/*表示使用英文字符*/

#defineALPHABET_START'a'/*头一个字符,可以用'A'*/

#defineCOUNT_OF_ALPHABET26/*字母字符的个数*/

#defineDIGIT2/*表示使用数字字符*/

#defineDIGIT_START'0'/*头一个字符*/

#defineCOUNT_OF_DIGIT10/*数字字符的个数*/

#defineSIGN_TYPEALPHABET/*本实例选用英文字符*/

constchar*fifo_file="./myfifo";/*仿真FIFO文件名*/

charbuff[MAXLEN];/*缓冲区*/

/*功能:生产一个字符并写入仿真FIFO文件中*/

intproduct(void)

{

intfd;

unsignedintsign_type,sign_start,sign_count,size;

staticunsignedintcounter=0;

/*打开仿真FIFO文件*/

if((fd=open(fifo_file,O_CREAT|O_RDWR|O_APPEND,0644))<0)

{

printf("Openfifofileerrorn");

exit(1);

}

sign_type=SIGN_TYPE;

switch(sign_type)

{

caseALPHABET:/*英文字符*/

{

sign_start=ALPHABET_START;

sign_count=COUNT_OF_ALPHABET;

}

break;

caseDIGIT:/*数字字符*/

{

sign_start=DIGIT_START;

sign_count=COUNT_OF_DIGIT;

}

break;

default:

{

return-1;

}

}/*endofswitch*/

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:writeerrorn");

return-1;

}

lock_set(fd,F_UNLCK);/*解锁*/

close(fd);

return0;

}

intmain(intargc,char*argv[])

{

inttime_step=1;/*生产周期*/

inttime_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);

}

本实验中的消费者程序的源代码如下所示。

/*customer.c*/

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#include<fcntl.h>

#defineMAX_FILE_SIZE100*1024*1024/*100M*/

constchar*fifo_file="./myfifo";/*仿真FIFO文件名*/

constchar*tmp_file="./tmp";/*临时文件名*/

/*资源消费函数*/

intcustoming(constchar*myfifo,intneed)

{

intfd;

charbuff;

intcounter=0;

if((fd=open(myfifo,O_RDONLY))<0)

{

printf("Functioncustomingerrorn");

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);

return0;

}

/*功能:从sour_file文件的offset偏移处开始

将count个字节数据复制到dest_file文件*/

intmyfilecopy(constchar*sour_file,

constchar*dest_file,intoffset,intcount,intcopy_mode)

{

intin_file,out_file;

intcounter=0;

charbuff_unit;

if((in_file=open(sour_file,O_RDONLY|O_NONBLOCK))<0)

{

printf("Functionmyfilecopyerrorinsourcefilen");

return-1;

}

if((out_file=open(dest_file,

O_CREAT|O_RDWR|O_TRUNC|O_NONBLOCK,0644))<0)

{

printf("Functionmyfilecopyerrorindestinationfile:");

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);

return0;

}

/*功能:实现FIFO消费者*/

intcustom(intneed)

{

intfd;

/*对资源进行消费,need表示该消费的资源数目*/

customing(fifo_file,need);

if((fd=open(fifo_file,O_RDWR))<0)

{

printf("Functionmyfilecopyerrorinsource_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);

return0;

}

intmain(intargc,char*argv[])

{

intcustomer_capacity=10;

if(argc>1)/*第一个参数指定需要消费的资源数目,默认值为10*/

{

sscanf(argv[1],"%d",&customer_capacity);

}

if(customer_capacity>0)

{

custom(customer_capacity);

}

exit(EXIT_SUCCESS);

}

(3)先在宿主机上编译该程序,如下所示:

$makeclean;make

(4)在确保没有编译错误后,交叉编译该程序,此时需要修改Makefile中的变量

CC=arm-linux-gcc/*修改Makefile中的编译器*/

$makeclean;make

(5)将生成的可执行程序下载到目标板上运行。

4.实验结果

此实验在目标板上的运行结果如下所示。实验结果会和这两个进程运行的具体过程相关,希望读者能具体分析每种情况。下面列出其中一种情况:

终端一:

$./producer120/*生产周期为1s,需要生产的资源数为20个*/

Writelocksetby21867

Releaselockby21867

Writelocksetby21867

Releaselockby21867

……

终端二:

$./customer5/*需要消费的资源数为5个*/

Enjoy:abcde/*消费资源,即打印到屏幕上*/

Writelocksetby21872/*为了仿真FIFO结构,进行两次复制*/

Releaselockby21872

在两个进程结束之后,仿真FIFO文件的内容如下:

$catmyfifo

fghijklmnopqr/*a~e的5个字符已经被消费,就剩下后面15个字符*/

6.6.2多路复用式串口操作1.实验目的

通过编写多路复用式串口读写,进一步理解多路复用函数的用法,同时更加熟练掌握Linux设备文件的读写方法。

2.实验内容

本实验主要实现两台机器(宿主机和目标板)之间的串口通信,每台机器都可以发送和接收数据。除了串口设备名称不同(宿主机上使用串口1:/dev/ttyS0,而在目标板上使用串口2:/dev/ttyS1),两台机器上的程序基本相同。

3.实验步骤

(1)画出流程图

如图6.5所示为程序流程图,两台机器上的程序使用同样的流程图。

图6.5宿主机/目标板程序的流程图

(2)编写代码。

编写宿主机和目标板上的代码,在这些程序中用到的open_port()和set_com_config()函数请参照6.4节。这里只列出宿主机上的代码。

/*com_host.c*/

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<string.h>

#include<fcntl.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<errno.h>

#include"uart_api.h"

intmain(void)

{

intfds[SEL_FILE_NUM],recv_fd,maxfd;

charbuff[BUFFER_SIZE];

fd_setinset,tmp_inset;

structtimevaltv;

unsignedloop=1;

intres,real_read,i;

/*将从串口读取的数据写入这个文件中*/

if((recv_fd=open(RECV_FILE_NAME,O_CREAT|O_WRONLY,0644))<0)

{

perror("open");

return1;

}

fds[0]=STDIN_FILENO;/*标准输入*/

if((fds[1]=open_port(HOST_COM_PORT))<0)/*打开串口*/

{

perror("open_port");

return1;

}

if(set_com_config(fds[1],115200,8,'N',1)<0)/*配置串口*/

{

perror("set_com_config");

return1;

}

FD_ZERO(&inset);

FD_SET(fds[0],&inset);

FD_SET(fds[1],&inset);

maxfd=(fds[0]>fds[1])?fds[0]:fds[1];

tv.tv_sec=TIME_DELAY;

tv.tv_usec=0;

printf("Inputsomewords(enter'quit'toexit):n");

while(loop&&(FD_ISSET(fds[0],&inset)||FD_ISSET(fds[1],&inset)))

{

tmp_inset=inset;

res=select(maxfd+1,&tmp_inset,NULL,NULL,&tv);

switch(res)

{

case-1:

{

perror("select");

loop=0;

}

break;

case0:/*Timeout*/

{

perror("selecttimeout");

loop=0;

}

break;

default:

{

for(i=0;i<SEL_FILE_NUM;i++)

{

if(FD_ISSET(fds[i],&tmp_inset))

{

memset(buff,0,BUFFER_SIZE);

/*读取标准输入或者串口设备文件*/

real_read=read(fds[i],buff,BUFFER_SIZE);

if((real_read<0)&&(errno!=EAGAIN))

{

loop=0;

}

elseif(!real_read)

{

close(fds[i]);

FD_CLR(fds[i],&inset);

}

else

{

buff[real_read]='';

if(i==0)

{/*将从终端读取的数据写入串口*/

write(fds[1],buff,strlen(buff));

printf("Inputsomewords

(enter'quit'toexit):n");

}

elseif(i==1)

{/*将从串口读取的数据写入普通文件中*/

write(recv_fd,buff,real_read);

}

if(strncmp(buff,"quit",4)==0)

{/*如果读取为‘quit’则退出*/

loop=0;

}

}

}/*endofifFD_ISSET*/

}/*fori*/

}

}/*endofswitch*/

}/*endofwhile*/

close(recv_fd);

return0;

}

(3)接下来,将目标板的串口程序交叉编译,再将宿主机的串口程序在PC机上编译。

(4)连接PC的串口1和开发板的串口2。然后将目标板串口程序下载到开发板上,分别在两台机器上运行串口程序。

4.实验结果

宿主机上的运行结果如下所示:

$./com_host

Inputsomewords(enter'quit'toexit):

Hello,Target!

Inputsomewords(enter'quit'toexit):

I'mhostprogram!

Inputsomewords(enter'quit'toexit):

Byebye!

Inputsomewords(enter'quit'toexit):

quit/*这个输入使双方的程序都结束*/

从串口读取的数据(即目标板中发送过来的数据)写入同目录下的recv.dat文件中。

$catrecv.dat

Hello,Host!

I'mtargetprogram!

Byebye!

目标板上的运行结果如下所示:

$./com_target

Inputsomewords(enter'quit'toexit):

Hello,Host!

Inputsomewords(enter'quit'toexit):

I'mtargetprogram!

Inputsomewords(enter'quit'toexit):

Byebye!

与宿主机上的代码相同,从串口读取的数据(即目标板中发送过来的数据)写入同目录下的recv.dat文件中。

$catrecv.dat

Hello,Target!

I'mhostprogram!

Byebye!

Quit

请读者用poll()函数实现具有以上功能的代码。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭