嵌入式Linux实时操作系统及应用编程代码与答案_第1页
嵌入式Linux实时操作系统及应用编程代码与答案_第2页
嵌入式Linux实时操作系统及应用编程代码与答案_第3页
嵌入式Linux实时操作系统及应用编程代码与答案_第4页
嵌入式Linux实时操作系统及应用编程代码与答案_第5页
已阅读5页,还剩53页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

附录A习题参考答案

嵌入式Linux实时操作系统及应用编程

第1章

1.嵌入式系统是指操作系统和功能软件集成于计算机硬件系统之中。简单的说就是系统

的应用软件与系统的硬件一体化,类似与BIOS的工作方式。具有软件代码小,高度自动化,响

应速度快等特点。特别适合于要求实时的和多任务的体系。根据IEEE(国际电气和电子」.程

师协会)的定义:嵌入式系统是“用于控制、监视或者辅助操作机器和设备的装置”(原文为

devicesusedtocontrol,monitor,orassisttheoperationofequipment,machineryorplants)o

简单地讲就是嵌入到对象体中的专用计算机系统。

嵌入式系统一般有3个主要的组成部分:硬件、实时操作系统以及应用软件。

・硬件:包括处理器、存储器(ROM、RAM)、输入输出设备、其他部分辅助系统等。

•实时操作系统(Real-TimeOperatingSystem,RTOS):用于管理应用软件,并提供一种机制,

使得处理器分时地执行各个任务并完成一定的时限要求。

・应用软件:实现具体业务逻辑功能。

2.嵌入式系统的三要素是嵌入、专用、计算机;其中嵌入性指的是嵌入到对象体系中,有对

象环境要求;专用性是指软、硬件按对象要求裁减;计算机指实现对象的智能化功能。广义

地说一个嵌入式系统就是一个具有特定功能或用途的计算机软硬件集合体,即以应用为中心、

以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗

严格要求的专用计算机系统。

3.嵌入式实时操作系统(Real-TimeOperatingSystem,RTOS)是指操作系统本身要能在一

个固定时限内对程序调用(或外部事件)做出正确的反应,亦即对时序与稳定性的要求十分严

格。

Fl前国际较为知名的有:VxWorksNeutrinoRTOS>NucleusPkis^OS/9、VRTX、LynuxOS,

RTLinux、BlueCatRT等。

4.嵌入式系统一般由硬件层、中间层、软件层和功能层组成。其作用分别如下:

(1)硬件层:由嵌入式微处理器、外围电路和外设组成。外围电路有:电源电路、复位

电路、调试接口和存储器电路,就构成一个嵌入式核心控制模块。

操作系统和应用程序都可以固化在ROM或者Flash中。为方便使用,有的模块在此基础

上增加了LCD.键盘、USB接口,以及其他一些功能的扩展电路。

(2)中间层:硬件层与软件层之间为中间层,也称为BSP(BoardSupportPackage,板

级支持包)。

作用:将系统软件与底层硬件部分隔离,使得系统的底层设备驱动程序与硬件无关:

功能:一般应具有相关硬件的初始化、数据的输入/输出操作和硬件设备的配置等功能。BSP

是主板硬件环境和操作系统的中间接口,是软件平台中具有硬件依赖性的那一部分,主要目

的是为了支持操作系统,使之能够更好地运行于硬件主板上。

(3)软件层:主要是操作系统,有的还包括文件系统、图形用户接口和网络系统等。操作

系统是一个标准的内核,将中断、I/O、定时器等资源都封装起来,以方便用户使用。

(4)功能层:由基于操作系统开发的应用程序组成,用来完成对被控对象的控制功能。功

能层是面向被控对象和用户的,为了方便用户操作,往往需要具有友好的人机界面。

5.非占先式,调度法也称作合作型多任务(cooperativemultitasking),各个任务彼此合作共享

一个CPU。中断服务可以使一个高优先级的任务由挂起状态变为就绪状态。但中断服务以后

控制权还是回到原来被中断了的那个任务,直到该任务主动放弃CPU的使用权时,那个高优

先级的任务才能获得CPU的使用权。当系统响应时间很重要时,要使用占先式(preemptive)

内核。最高优先级的任务一旦就绪,总能得到CPU的控制权。当一个运行行的任务使一个比

它优先级高的任务进入了就绪态,当前任务的CPU使用权就被剥夺了,或者说被挂起了,那

个高优先级的任务立刻得到了CPU的控制权。

6.在实时系统中,如果系统在指定的时间内未能实现某个确定的任务,会导致系统的全面失

败,这样的系统被称为强实时系统或硬实时系统。强实时系统响应时间一般在亳秒或微秒级。

在弱实时系统中,虽然响应时间同样重要,但是超时却不会发生致命的错误。其系统响应时间

在亳秒至秒的数量级上,其实时性的要求比强实时系统要差一些。

7.嵌入式系统的设计步骤及各部分的主要工作如下。

(1)需求分析阶段,罗列出用户的需求;

(2)体系结构设计阶段,描述系统的功能如何实现;

(3)详细设计阶段,进行硬件系统与软件系统的分类划分,以决定哪些功能用硬件实现,哪些

用软件实现;

(4)系统集成,把系统的软件、硬件和执行装置集成在一起,进行调试,发现并改进在设计过

程中的错误;

(5)系统测试,对设计好的系统进行测试,看其是否满足给定的要求。

8.Linux作为嵌入式操作系统的优势主要有以下几点:

(1)可应用于多种硬件平台。Linux已经被移植到多种硬件平台,这对于经费,时间

受限制的研究与开发项目是很有吸引力的。原型可以在标准平台上开发后移植到具体的硬件

上,加快了软件与硬件的开发过程。Linux采用一个统一的框架对硬件进行管理,从一个硬件

平台到另一个硬件平台的攻动与上层应用无关。

(2)Linux的高度模块化使添加部件非常容易。本身内置网络支持,而目前嵌入式系统

对网络支持要求越来越高,

(3)Linux是一个和Unix相似、以内核为基础的、具有完全的内存访问控制,支持大量

硬件(包括X86,Alpha、ARM和Motorola等现有的大部分芯片)等特性的一种通用操作系统。

(4)Linux可以随意地配置,不需要任何的许可证或商家的合作关系。其程序源码全部

公开,任何人可以修改并在GUN通用公共许可证(GNUGeneralPublicLicense)下发行。这样,

开发人员可以对操作系统进行定制,适应其特殊需要。

(5)Linux带有Unix用户熟悉的完善的开发工具,几乎所有的Unix系统的应用软件都已移

植到了Linux」:。其强大的语言编译器GCC,C++等也可以很容易得到,不但成熟完善,而且

使用方便。

9.(参考答案)Linux执号进程调度一般是在以下情况发生的:

(1)正在执行的进程运行完毕;

(2)正在执行的进程调用阻塞原语将自己阻塞起来进入等待状态;

(3)正在执行的进程调用了P原语操作,从而因资源不足而被阻塞;或调用了V原语操作激

活了等待资源的进程队列;

(4)执行中的进程提出UO请求后被阻塞;

(5)系统分配的时间片已经用完;

以上都是CPU为不可剥夺方式下的引起进程调度的原区。在CPU方式是可剥夺时,还有下面

的原因:

(6)就绪队列中的某个进程的优先级变得高于当前运行进程的优先级,从而也将引起

进程调度。

嵌入式Linux实时操作系统及应用编程

第2章

一.填空题:

1.改变目录位置至用户的工作目录

2.改变目录位置至相对路径user的目录下

3.查看当前目录下的文件

4.查看文件.bash_profile的内容

5.分页查看inittab文件内容

6.将目录/tmp下的文件filel复制到当前目录下,文件名为file2

7、将文件filel移到目录dirl下,文件名仍为filel

8、建立一新目录dir1

9、删除目录dirl,但dirl下必须没有文件存在,否则无法删除

10、删除文件名中有五个字符且前四个字符为file的所有文件

11.文件config的内容依次显示到屏幕卜

12.以分页方式查看文件名filel的内容

13.以分页方式查看文件名filel的内容

14.显示目录dirl的总容量

15.对于目录dir1,设定成任何使用者皆有读取及执行的权利,但只有所有者可做修改

16、对于文件fi1e1,设定只有所有者可以读、写和执行的权利。

17、将文件file4链接至文件fi1e3o

18、寻找文件fi1e1中包含字符串abc所在行的文本内容。

19、自根目录下寻找文件filel的路径。

20、比较目录dir1与dir2内各文件的不同之处。

二、单项选择题

1.A2.B3.D4.C5.B

6.C7.A8.C9.D10.B

11.A12.D13.D14.B15.B

16.B17.A18.DI9.B20.B

嵌入式Linux实时操作系统及应用编程

第3章

一.填空题:

1.next

2.命令模式

3.预处理、编译、汇编和连接

4.stepnext

5.末行模式

6.预处理链接

7.汇编

8.wtest,txt

二、综合题

1.参考答案:

prl:prog,osubr.o

gcc-oprlprog,osubr.o

prog,o:prog,cprog,h

gcc-c-oproR.oprog,c

subr.o:subr.csubr.h

gcc-c-osubr.osubr.c

2.(1)

hello:main,olist,osymbol,otable,o

gcc-oprogmain.olist,osymbol,otable,o

main,o:main,ctable,hsymbol,hlist,h

gcc-c-omain,omain,c

list,o:list,clist,h

gcc-c-olist.olist.c

symbol,o:symbol.csymbol,h

gcc-c-osymbol,osymbol,c

table,o:table,ctable,hsymbol,hlist,h

gcc-c-otable,otable,c

clean:

rmhello*.o

(2)mount-tnfs-onoclock192.168.0.10:/home/armtest/hello/mnt

3.

hello,c:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include"hello,h”

intmain(intargc,char*argv[])

(

printf(^HelloWorld!\n,");

message();

return0;

)

hello.h:

voidmessage(void);

message,c:

#include<stdio.h>

voidmessage(void){

prinlf("Thisisamessage!\nz,);

)

三.选择题

1.C2.A3.B4.B5.B6.C

7.C8.D9.D10.A11.A

嵌入式Linux实时操作系统及应用编程

第4章

选择题

LA2.C3.D4.1)5.C

6.B7,C8.A9.D10.D

11.D12.D13.D14.B15.D

16.B17.A18.C19.C20.C

二.简答题

LLinux内核的编译菜单有好几个版本,运行:

(1)makeconfig:进入命令行,可以一行一行的配置,但使用不十分方便。

(2)makemenuconfig:大多数开发人员使用的Linux内核编译菜单,使用方便。

(3)iiuikcxcunGg:在2.4.X以及以前版本中xcunfig菜单是基丁TCL/TK的图形库的。

2.在完成内核的裁减之后,内核的编译就只要执行以下几条命令:

makeclean编译内核之前先把环境给清理干净。有时你也可以用makercalclcan或make

mrproper来彻底清除相关依赖,保证没有不正确的.。文件存在。

makedep编译相关依赖文件

makezlmage创建内核镜像文件

makemodules创建内核模块,若不创建内核模块,这步可以不要。

makeinstall把相关文件拷贝到默认的目录。在给嵌入式设备编译时这步可以不耍,因为

具体的内核安装还需要你手进行。

3.此命令是装载压缩映像工件zlmage到flash存储器中,地址是kemel分区,并采用xmodem传输

协议。

4.此命令是设置网卡1的地址,掩码为255.255.255Q不写netmask参数则默认为

5.此命令将nfs服务的共享目录sharedir加载到/mnt/nfs。

6、此命令是装载根文件系统root.cramfs到flash存储器中,地址是根文件系统分区,并

采用xmodem传输协议。

7、这个命令的操作同时进行了分区和格式化,0〜128K存放vivi,128K〜192K存放VIVI

控制台指令,192K-1216K存放kernel,1216K-4288K存放root,其余部分存放应用程序。

嵌入式Linux实时操作系统及应用编程

第5章

一.选择题

1.B2.C3.C4.C5.D6.C

二.综合应用题

1.

Tomismyfriend

Jackismyfriend

Harryismyfriend

2.

(1)程序注释

#!/bin/sh定义实用的shell

#

n/etc/rc.d/rc.httpd注释行,凡是以星号开始的行均为注释行。

#

#Start/stop/restarttheApachewebserver.

#

#TomakeApachestartautomaticallyatboot,makethis

#fileexecutable:chmod755/etc/rc.d/rc.httpd

#

casew$rin枇ase结构开始,判断“位置参数”决定执行的操作。本程序携带一个“位置

参数”,即$1

,start,)#若位置参数为start

/usr/sbin/apachec11start;;#启动httpd进程

'stop')#若位置参数为stop

/usr/sbin/apachect1stop;;#关闭httpd进程

'restart*)#若位置参数为stop

/usr/sbin/apachect1restart;;#重:新启动httpd进程

*)#若位置参数不是start、stop或restart时

echo"usage$0startstop|restart;;#显示命令提示信息:程序的调用方法

esacrtcase结构结束

(2)程序的功能是启动,停止或重新启动httpd进程

(3)程序的调用方式有三种:启动,停止和重新启动。

3.

#!/bin/sh

FILENAME:

echo**Inputfilename:"

readFILENAME

if[-c-FILENAME"]

then

cp$FILENAME/dev

fi

4.

#/bin/bash

typesetfirstsecond

read-p"Inputthefirstnumber:*first

read-p"Inputthesecondnumber:second

result=$[$first+$second]

echo"resultis:Sresult*

exit0

5.

#!/bin/sh

i=l

while[i-le50]

do

if[-d/userdata];then

mkdir-p/userdata/user$i

chmod754/userdata/user$i

echo"user$i”

let=i+1〃(或i=$(($i+l))

else

mkdir/userdata

mkdir-p/userdata/user$i

chmod754/userdata/user$i

echo'user$i”

let"i=i+1"(或i=$(($i+l))

fi

done

嵌入式Linux实时操作系统及应用编程

第6章

一.简答题

1.使用虚拟地址寻址整个系统的主存和辅存的方式在现代操作系统中被称为虚拟内存。MMU

便是实现虚拟内存的必要条件。嵌入式处理器如果存在MMU,由于在MUU具备内存地址映射

和寻址功能,操作系统会使用它完成从虚拟地址到物理地址的转换,所有的应用程序只需

要使用虚拟地址寻址数据,

虚拟内存的管理方法使系统既可以运行体积比物理内存还要大的应用程序,也可以实现

“按需调页”策略,既满足了程序的运行速度,又节约了物理内存空间。

2.进程内存区域涉及到5种数据段,即:

①代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存

中的镜像。

②数据段:数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态

分配的变量和全局变量。

③BSS段:BSS段包含了程序中未初始化的全局变量,在内存中BSS段全部置零。

④堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动

态扩张或缩减。当进程调用malloc等函数分配内存时;新分配的内存就被动态添加到堆上(堆

被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

⑤栈:栈是用户存放程序临时创建的局部变量,也就是说函数括弧“{}”中定义的变量(但

不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用

时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存

放回栈中。

3.在Linux系统中,内核在最高级执行,也称为“系统态”,在这一级任何操作都可以执行。

而应用程序则执行在最低级,即所谓的“用户态”。在这一级处理器禁止对硬件的直接访问

和对内存的未授权访问。模块是在所谓的“内核空间”中运行的,而应用程序则是在“用户

空间”中运行的。它们分别引用不同的内存映射,也就是程序代码使用不同的“地址空间”。

4.共享内存区域是被多个进程共享的一部分物理内存。如果多个进程都把该内存区域映射到

自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域

进行通信。共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了

数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。这块共享虚拟内存的页面,

出现在每一个共享该页面的进程的页表中。但是它不需要在所有进程的虚拟内存中都有相同

的虚拟地址。

5.内存管理利用虚拟文件系统支持交换,交换进程(sw叩d)定期由调度程序调度,这也是内存

管理依赖于进程调度的唯--原因。当一个进程存取的内存映射被换例时,内存管理向文件系统

发出请求,同时,挂起当前正在运行的进程。

二.编程题

1.参考程序:

#include<stdlib.h>

structtest

(

inta[10];

charb[20];

)

intmain()

{

structtest*ptr=calloc(sizeof(structtest),10);

)

2.参考程序:

#include<sys/types.h>

#include<sys/stat.h>

??include<fcntl.h>

#include<unistd.h>

#include<sys/mman.h>

main()

{

intfd;

void*start;

structstatsb;

fd=open(<Vetc/passwd,>,0RDONLY);/*打开/etc/passwd*/

fstat(fd,&sb);/*取得文件大小*/

start=mmap(NULL,sb.st_size,PROT_READ,M/\P_PRIVATE,fd,0);

if(start==MAP_FAILED)/*判断是否映射成功*/

return;

printf("%s”,start);

munma(start,sb.st_size);/*解除映射*/

closed(fd);

)

嵌入式Linux实时操作系统及应用编程

第7章

一、单项选择题

1.A2.B3.A4.D5.6.A7.C

二.编程题

1.

(1)

Voidmain(void)

(

intfid;

fid=open(/test.txtw,O_RDWR10_CREAT);

if(fid=-l)

(

Printf("openorcreateerror'n");

exit(0);

)

Close(fid);

)

(2)

objects=main.o

exec=main

all:$(objects)

gcc-o$(exec)$(objects)

main.o:main.c

gcc-cmain,c

c1ean:

rm-r$(exec)$(objects)

2.参考程序:

#include<sys/types.h>

#inclu(le<sys/stat.h>

#include<fcntl.h>

/include<stdlib.h>

#include<unistd.h>

#include<stdio.h>

#defineBUFFER_SIZE1024

intmain(intargc.char**argv)

intfrom_fd,to_fd;

intbytcs_rcad,byles_wriic;

charbuffer[BUFFER_SIZE];

char*ptr;

if(argc!=3){

fprinll'(stderr,"Usage:%sfromfilctofile\n\a",argvlOJ);

exit(l);

)

/*打开源文件*/

if((frotn_fd=open(argv[1],O_RDONLY))==-1){

fprintf(stderr."Open%sEiTor:%s\n".argv|1|,strerror(emio);;

exit(l);

)

/*创建目的文件*/

if((to_fd=open(argv⑵,O_WRONLY|O_CREAT.S」RUSR|S」WUSR))==-1){

fprintf(stdcrr,"Opcn%sError:%s\n",argv[2],strcrror(eirno));

cxit(l);

)

/*以下代码是一个经典的拷贝文件的代码*/

whilc(byics_rcad=rcad(from_fd,buffer,BUFFER_SIZE)){

if((bytes_read==-1)&&(errno!=EINTR))break:/*发生读错误,退出循环*/

elseif(bylcs_read>O){

pti-buffer:

while(by(es_write=wrile(to_fd,ptr,bytes_read)){

it((bytes_wnte=-l)&<&(errno!=fclNIK))break:/*若写错误,退出循环*/

/*写完了所有读的字节*/

elseif(bytes_write==bytes_read)break;/*读写字节不等退出循环*/

elseif(bytes_write>O){/*只写了一部分,继续写*/

ptr+=b>/tcs_wrilc;

bytes_read-=bytes_write:

)

)

if(bytes_wri:e==-1)break;/*写的时候发生的致命借误*/

)

}

close(from_fd);

close(to_fd);

exit(O);

I

3.参考程序:

#include<stdio.h>

structstudent{

charname[10];

intage;

);

intmain。

(

FILE*fp;

inii;

structstudentboya[2],boyb[2],*pp.*qq:

if((fp=fopcn("7-6.txt"."w+,,))==NULL)〃打开文件

|

printf("Cannotopenfile,exit

return-1;

I

pp=boya;

qq=boyb;

prinlf("plcaseinputdala:\n");〃输入学生信息

for(i=0;i<2;i++,pp++)

scanf("%s%d",pp->naine,&pp->age);

pp=boya;

fwrite(pp,sizeof(struccstudent),2,fp);〃把学生信息写入文件

rewind(fp);〃重定位文件

fread(qq,sizeof(structstudent),2,fp);〃从文件中读取学生信息

prin(f("namc\l\tagc\n"i;

for(i=0;i<2;i++,qq++)

printf("%s\t\t%d\n",qq->name,qq->age);

fclose(fp);

return0;

4.参考程序如下:

嵌入式Linux实时操作系统及应用编程

第8章

一、单项选择题

1.B

2.A

3.A

4.D

5.C

6.D

7、C

8、I)

9、C

10、B

二.阅读程序题

1.答案要点:

(1)将数据缓冲区清0

(2)创建管道

(3)创建子进程

(4)关闭子进程写描述符

(5)子进程读取管道内容

(6)关闭子进程读描述符

(7)父进程运行控制语句

(8)关闭父进程的读描述符

(9)将数据写入缓冲区

(10)关闭父进程写描述符

三.程序设计

1.参考程序如下:

voidmain(){

kcytuniquekey;/*定义一个IPC关键字*/

intid;

structsembuflock_it;

unionsemunoptions;

inti;

unique_key=ftoka');/*生成关键字,字符'a'是一个随机种子*/

/*创建一个新的信号量集合*/

id=semget(unique_key,1,IPC_CREAT|IPC_EXCL|0666);

printf(?,semaphoreid=%d\n”,id);

options,val=1;/*设置变量值*/

semctl(id,0,SETVAL,options);/*设置索引0的信号量*/

/*打印出信号量的值"

i=scmctl(id,0,GETVAL,0);

printf("valueofsemaphoreatindex0is%d\n/,,i);

/*下面重新设置信号量*/

lock_it.sem_num=设置哪个信号量*/

lockit.scmop=~1;/*定义操作*/

lock_it.sem_flg=IPC_NOWAIT;/*操作方式*/

if(semop(id,&lock_it,1)==-1){

printf(*cannotlocksemaphore.\n");

exit(1);

)

i=semctKid,0,GETVAL,0);

printf("valueofsemaphoreatindex0is%d\n',i);

/*清除信号量*/

semctl(id,0,1PC_RMID,0);

)

2.参考程序:

(1)init.c清单

#include<unistd.h>

#include<signal,h>

#include<sys/param.h>

^include<sys/types.h>

#include<sys/stat.h>

voidinit_daemon(void)

intpid;

inti;

if(pid=fork())

exitS);〃是父进程,结束父进程

elseif(pid<0)

exit(1);〃fork失败,退出

〃是第一子进程,后台继续执行

setsidO;

〃第一子进程成为新的会话组长和进程组长并与控制终端分离

if(pid=fork0)

exit(0);〃是第一子进程,结束第一子进程

elseif(pid<0)

exit(1);〃fork失败,退出

〃是第二子进程,继续

〃第二子进程不再是会话组长

for(i=0;i<N0FILE;++i)〃关闭打开的文件描述符

close(i);

chdir("/tmp");〃改变工作目录到/tmp

umask(0);//重设文件创建掩模

return;

)

(2)test,c清单

#include<stdio.h>

#include<time,h>

voidinit_daemon(void);〃守护进程初始化函数

main()

(

FILE*fp;

time_tt;

initdaemon。;〃初始化为Daemon

while(l)〃每隔一分钟向test,log报告运行状态

(

sleep(60);//睡眠一分钟

if((fp=fopen("test,log","a"))>=0)

(

t=time(0);

reat%s\nv,asetime(localtime(&t)));

fclose(fp);

}

}

)

以上程序在RedHaiUnux6.0下编译通过。步骤如下:

编译:gcc-g-otestinit.ctest,c

查看进程:ps-ef

程的各种特性满足上面的要求。

3.参考程序:

ttdefineINPUT0

^defineOUTPUT1

voidmain(){

intfile„descriptors[2];

/*定义子进程号*/

pid_tpid;

charbuf[256];

intreturnedcount;

/*创建无名管道*/

pipe(filedcscriptors);

/*创建子进程*/

if((pid=forkO)==-1){

printf(''Errorinfork\n");

exit(1);

)

/*执行子进程*/

if(pid==0){

printf(^inthespawned(child)process…\n");

/*子进程向父进程写数据,关闭管道的读端*/

close(file_descriptors[INPUT]);

write(filedescriptors[OUTPUT],“testdata”,strlen(^testdata"));

exit(0);

)else{

/*执行父进程*/

printfC*inthespawning(parent)process...\n*);

/*父进程从管道读取子进程写的数据,关闭管道的写端*/

close(file_descriptors[OUTPUT]);

returncdcount=read(filedescriptors[INPUT],buf,sizeof(buf));

printf(,z%dbytesofdatareceivedfromspawnedprocess:%s\n”,

returnedcount.buf);

)

)

在Linux系统下,有名管道可由两种方式创建:命令行方式mknod系统调用和函数mkfifo。

下面的两种途径都在当前目录下生成了一个名为myfifo的有名管道:

方式一:mkfifo("myfifo","rw");

方式二:mknodmyfifop

生成了有名管道后,就可以使用一般的文件I/O函数如open、closerread,write等来对它

进行操作。下面即是一个同单的例子,假设我们已经创建了一个名为myfifo的有名管道。

/*进程一:读有名管道*/

^include

ttinclude

voidniain(){

FILE*in_file;

intcount=1;

charbuf[80];

infile=fopen(mypipe,r);

if(infile==NULL){

printf("Errorinfdopen.\n?,);

exit(1);

}

while((count=fread(buf,1,80,infile))>0)

printf("receivedfrompipe:%s\n”,buf);

fclose(infile);

)

/*进程二:写有名管道*/

#include

^include

voidmain(){

FILE*out.file;

intcount=1;

charbuf[80];

out_file=fopen(,zmypipe*,"w");

if(out_file--NULL){

printf(z,Erroropeningpipe.");

exit(1);

)

sprintf(buf,z,thisistestdataforthenamedpipeexample'd');

fwrite(buf,1,80,out_file);

fclose(outfile);

)

嵌入式Linux实时操作系统及应用编程

第9章

一、简答题

1.参考答案:

Mutex互斥量,用于操作某个临界资源时对该资源上锁,以实现互斥地对独占资源的使用。(3

分)

Scmophorc信号灯,信号灯内有一计数器,可以用于对多个同类资源的分配。当资源用完时,

申请资源的线程会在信号量上睡眠,有线程释放资源时,再将该线程唤醒继续运行。(3分)

Condition条件变量,条件变量用于等待信号。当•个线程需要等待某个信号时,就可到条件变

量上等待,当信号具备时,系统会唤醒该线程继续运行。(4分)

2.参考答案:

本地:共享内存+信号量,适合于大展数据传输。Linux支持系统V和POSIX的共享内存和

信号量。(5分)

远程:Sockcl+应用协议。适合于跨网络的(大量)数据传输。Linux支持BSD的socket。应用

层协议需要自行设计。(5分)

3.答案要点:程序是编译后形成的可执行代码,是静止的。进程是程序的•次执行,是活动

的。线程是进程的可执行单元,同一进程的不同线程共享进程的资源和地址空间。

4.两种实现方法,一种是继承Thread,另外一种是实现接口Runnable。

同步的实现方法有两种,分别是synchronized,wait与notify。用synchronized可以对一段代码、

一个对象及一个方法进行加锁。用wait与notify可以使穴■象处于等待及唤醒方式导致同步,因

为每个对象都直接或间接的继承了Object类。

5.参考答案:(每小点1分)

Linux执行进程调度一般是在以卜情况发生的:

(1)正在执行的进程运行完毕;

(2)正在执行的进程调用阻塞原语将自己阻塞起来进入等待状态:

(3)正在执行的进程调用了P原语操作,从而因资源不足而被阻塞;或调用了V原语快作激

活了等待资源的进程队列;

(4)执行中的进程提出UO请求后被阻塞;

(5)系统分配的时间片已经用完;

以上都是CPU为不可剥夺方式下的引起进程调度的原因。在CPU方式是可剥夺时,还有下面

的原因:

(6)就绪队列中的某个进程的优先级变得高于当前运行进程的优先级,从而也将引起进程调

度。

二.编程题

参考程序:

/*数据写入缓冲区*/

voidput(structprodcons*b,intdata)

{pthrcad_mutcx_lock(&b->lock);/*获得互斥锁*/

while((b->wrilepos+1)%BUFFER_SIZE==b->readpos){

printf(uwaitfornotfull\n");

pthread_cond_\vait(&b->notfull,&b->lock);

/*等待b->notfull,不满则跳出阻塞力

}

b->buffer[b->writepos]=data;/*写入数据*/

b->writepos++;

if(b->vvritepos>=BUFFER_SIZE)b->writepos=0;

pthread_cond_signal(&b->notempty);/*设置状态变量

pthread_mutex_unlock(&b->lock);/*释放互斥锁*/

}

/*从缓冲区中读出数据*/

intgel(struc(prodcons*b)

(

intdata;

pthread_mutex_lock(&b->lock);/*获得互斥锁*/

while(b->writcpos==b->rcadpos){

printf("waitfornotempty\nn);

pthrcad_cond_\vait(&b->notempty,&b->lock);

/*等待不空则跳出阻塞*/

}

data=b->buffer[b->readpos];/*读出数据*/

b->readpos++;

if(b->rcadpos>=BUFFER_SIZE)b->readpos=0;

pthread_cond_signal(&b->notfull);/*设置状态变量*/

pthread_inutex_unlock(&b->lock);/*释放互斥锁*/

returndata;

}

/*生产者进程*/

void*producedvoid*data)

intn;

for(n=0;n<1000;n++){

printf("put—>%d\n,'»n);

pul(&buffer,n);

put(&buffer,OVER);

printf("producerstopped!\nH);

returnNULL;

/*消费者进程*/

void*consuiner(void*data)

{intd;

while(1){

d=gct(&buffcr);

if(d==OVER)break;

printf("%d->get\nd);

piintf("consumcrstoppcd!\n");

returnNULL;

/*主函数*/

intmain(void)

{pthread_tth_a,th_b;

void*rctval;

init(&buffer);

pthrcad_crcatc(&th_a,NULL,producer,0);

pthread_create(&th_b,NULL,consumer,0);

/*等待生产者和消费者结束*/

pthreadjoin(th_a,&retval);

pthreadjoin(th_b,&retval);

return0;

第10章

一、单项选择题

LB2.B3.C4.A5.B6.C7、C8、B9、A10、B

二.编程题

1.参考程序:

#includo<stdio.h>

#include<stdlib.h>

#include<errno.h>

#include<string.h>

^include<sys/types.h>

"include<netinet/in.h>

^include<sys/socket.h>

#include<sys/wait.h>

Jtinclude<unistd.h>

#include<arpa/inet.h>

intmain(intargc,char**argv)

(

intsockfd;

structsockaddrinmyaddr;

unsignedintmyport,1isnum;

if(argv[l])

myport=atoi(argvfl]);

else

myport=7838;

if(argv[2])

lisnum=atoi(argv[2]);

else

lisnum=2;

if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1){

perror("socket");

exit(1);

)

elseprintfCsockelcreated\nw);

bzero(&my_addr,sizeof(myaddr));

myaddr.sin_family=PFINET;

myaddr.sinport=htons(mypoi't);

if(argv[3])my_addr.sin_addr.s_ciddr=inet_addr(argv[3]);

elsemyaddr.sinaddr.s_addr=INADDRANY;

if(bind(sockfd,(structsockaddr*)&myaddr,sizeof(structsockaddr))==-1)

{

perror("bind");

exit(1);

)

elseprintf("binded'n");

if(listen(sockfd,lisnum)==-1){

perror("listen");

exit(1);

)

elseprintf("beginlisten\n,/);

sleep(100);

close(sockfd);

return0;

}

编译程序用下列命令:

gcc-Wa11simple-listen,c

运行程序用如下命令:

./a.out78382

这将在你自己主机的所有IP地址是等待客户端连接。比如你的网卡lo的IP地址127.0.0.1,

又比如你的网卡ethO的IP地址192.168.0.100

如果要指定只在某个地址是开启监听服务,可以用下面的命令:

./a.out78382127.0.0.1

这样,客户端只能通过127.0.0.1的7838端口连接你的程序。

你可以开启〜个终端输入telnet127.0.0.17838米测试是否能连接成功。

同时可以用netstat-angrep7838命令来查看网络是否连接正常

2.参考程序:

"include<stdio.h>

#includc<stdlib.h>

include<errno.h>

#include<string.h>

#include<sys/types.h>

#include<netinet/in.h>

#includc<sys/sockot.h>

#include<sys/wait.h>

#includo<unistd.h>

#include<arpa/inet.h>

/************关于本文档********************************************

"filename:simple-accept.c

•purpose:演示最基本的网络编程步骤,开启服务端的监听,并接收每个客户端的连接请求

♦wroteby:zhoulifa(zhoulifa@163.com)周立发(http:〃zhoulifa.bokcc.com)

Linux爱好者Linux知识传播者SOHO族开发者最擅长C语言

♦datetime:2007-01-2412:41

*Note:任何人可以任意复制代码并运用这些文档,当然包括你的商业用途

*但请遵循GPL

*Hop。:希望越来越多的人贡献自己的力量,为科学技术发展出力

*科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!

intmain(intargc,char**argv)

intsockfd,new_fd;

socklentlen;

structsockaddr_inmy_addr,their_addr;

unsignedintmyport,lisnum;

if(argv[1])

myport=atoi(argv[l]);

else

myport=7838;

if(argv[2])

1isnum=atoi(argv⑵);

else

lisnum=2;

if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1){

perror("socket");

exit(1);

)

elseprintf("socketcreated\n/,);

bzei'o(&my_ciddr,sizeof(my_addr));

myaddr.sinfamily=PFINET;

my_addr.sin_port=htons(myport);

if(argv[3])myaddr.sinaddr.s_addr=inetaddr(argv[3]);

elsemyaddr.sinaddr.saddr=INADDRANY;

if(bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr))==-1)

{

perror("bind");

exit(1);

)

elseprintf("binded'n");

if(listen(sockfd,lisnum)==-1){

perror("listen");

exit(1);

)

elseprintf(''begin1isten\n,/);

while(l){

len=sizeof(structsockaddr);

if((newfd=accept(sockfd,(structsockaddr*)&their_addr,&lcn))==-1)

(

pcrror("accept");

exit(errno);

)

elseprintf("server:gotconnectionfrom%s,port%d,

socket%d\n,/,inetntoa(theiraddr.sinaddr),

ntohs(theiraddr.sinport),newfd);

)

close(sockfd);

return0;

}

编译程序用下列命令:

gcc-Wallsimple-acccpt.c

运行程序用如下命令:

./a.out78381127.0.0.1

另外开多几个客户端程疗连接上来,

程序输出结果如下:

server:gotconnectionfrom127.0.0.1,port15949,socket4

server:gotconnectionfrom127.0.0.1,port15950,socket5

server:gotconnectionfrom127.0.0.1,port15951,socket6

server:gotconnectionfrom127.0.0.1,port15952,socket7

3.参考程序:

服务器:

??include<sys/types.h>

#include<sys/socket.h>

#include<string.h>

#include<netinet/in.h>

^include<st

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论