1. 下列区域存取速度最快的是(c)
A. Flash B. DRAM C. CACHE D.磁盘
2. 哪些区域不能用来存储变量空间()
A. SDRAM B. CACHE(一、二级缓存) C. DDR2 D. L2SRAM DATA
3. CPU中数据总线的宽度会影响(d)
A.内存容量大小 B.系统运算速度 C.指令系统指令数量 D.寄存器宽度
4. 不能提高代码执行效率的是(cd)
A.多循环减少内循环的次数 B.将频繁调用的小函数改为内联函数
C. 使用递归函数 D.提高并行性 E.减少存储器引用
5. 中断响应时间是指(d)
A.从中断处理开始,到中断处理结束的时间 B.从中断请求开始,到中断处理结束的时间
C. 从中断请求开始,到中断处理开始的时间 D.从发出中断请求到进入中断处理所用的时间
1. 填写下面程序输出
#include<stdio.h>main()
{
int a[5] = {1, 2, 3, 4, 5};
int * ptr = (int*)(&a + 1);注意
printf("%d %d", *(a + 1), *(ptr - 1));
}
输出是____2 5_________;
2. 填写下面程序输出
#include <stdio.h>
main()
{
char p;
char buf[10] = {1, 2, 3, 4, 5, 6, 9, 8};
p = (buf+1)[5];
printf("%d", p);
}
输出是_____9________;
3. 以下变量和函数存储在ELF可重定位目标的哪些段总,请在注释中写上段名。
int valid; // __________
int last = -1; // __________
int tophat(int size, double brim_width); // __________
printf("How's your exam going?\n"); //__________
三、程序设计题
1. 写分配空间的程序void * getmm(int size, int align),分配size大小的空间,并根据align指定的字节数方式对齐。
int i,j; //直方图数组清0
for(i=0;i<256;i++)
m_histArray[i]=0;
//每行像素所占字节数
intlineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;
//中间变量
int temp;
//统计灰度直方图
for(i=0;i<m_imgHeight;i++){
for(j=0;j<m_imgWidth;j++){
temp=*(m_pImgData+i*lineByte+j);
m_histArray[temp]++;
}
}
三、问答题
1. 为何会出现优先级反转,如何解决?
答:高优先级任务需要等待低优先级任务释放资源,而低优先级任务又正在等待中等优先级任务的现象叫做优先级反转。
两种经典的防止反转的方法:
优先级继承策略:继承现有被阻塞任务的最高优先级作为其优先级,任务退出临界区,恢复初始优先级。
优先级天花板策略:优先级天花板是指将申请(占有)某资源的任务的优先级提升到可能访问该资源 的所有任务中最高优先级任务的优先级 ( 这个优先级称为该资源的优先级天花板 ) 。优先级继承策略对任务执行流程的影响相对较小,因为只有当高优先级任务申请已被低优先级任务占有的临界资源这一事实发生时,才抬升低优先级任务的优先级。而天花板策略是谁占有就直接升到最高。
2. winsock建立连接的实现步骤。
服务器端:socket()建立套接字,绑定bind()并监听listen(),用accept()等待客户端连接.
客户端:socket()建立套接字,连接connect()服务器,连接上后使用send()和recv(),在套接字上读写数据,直至数据交换完毕,closesocket()关闭套按字.
服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连接.该新产生的套接字使用send()和recv()读写数据,直至数据交换完毕,closesocket()关闭套接字.
~~~~~~~~~~~~~~~~~~~~~
扩展知识
~~~~~~~~~~~~~~~~~~~~~~
1. 请问什么叫中断源,中断请求,中断标志字,中断屏蔽字,中断响应,中断服务程序,中断嵌套?
中断:处理器一种工作状态的描述,因为处理器与很多外部电路相连并负责处理外部电路送来的各种信息(处在协同工作状态),如果遇有(外部电路送来)“急件”需要优先处理,处理器则须先停下“自己手头的工作”先去处理“急件”,这种先停下“自己手头的工作”去处理“急件”的过程,即为——中断。
中断源:即发出“急件”的地点(电路)。
中断请求:“紧急事件”须向处理器提出申请(发一个电脉冲信号),要求“中断”,即要求处理器先停下“自己手头的工作”先去处理“我的急件”,这一“申请”过程,称——中断请求。
中断标志字:处理器内部有一个寄存器,该寄存器存放的“二进制信息”是专门用来描述中断状态的(即:记载是否已经发生了中断),这组“二进制信息”被称为中断标志字。
中断屏蔽字:是描述“中断屏蔽”状态的一组“二进制信息”。
中断响应:处理器接受“中断请求”并“同意”中断的过程(这时须把“当前现场”的状态信息压入堆栈),称——中断响应。
中断服务程序:处理器处理“急件”,可理解为是一种服务,是通过执行事先编好的某个特定的程序来完成的,这种处理“急件”的程序被称为——中断服务程序。
中断嵌套:一个中断可以被另一个更急的“急件”所中断。也就是处理器正在执行着中断,又接受了更急的另一件“急件”,这种“急件”“加塞”的过程被称为——中断嵌套.
2. WinSock编程
使用WinSock API的编程,应该了解TCP/IP的基础知识。虽然你可以直接使用WinSock API来写网络应用程序,但是,要写出优秀的网络应用程序,还是必须对TCP/IP协议有一些了解的。
WinSock并不是一种网络协议,它只是一个网络编程接口,也就是说,它不是协议,但是它可以访问很多种网络协议,你可以把他当作一些协议的封装。现在的WinSock已经基本上实现了与协议无关。你可以使用WinSock来调用多种协议的功能。
那么,WinSock和TCP/IP协议到底是什么关系呢?
实际上,WinSock就是TCP/IP协议的一种封装,你可以通过调用WinSock的接口函数来调用TCP/IP的各种功能.例如我想用TCP/IP协议发送数据,你就可以使用WinSock的接口函数Send()来调用TCP/IP的发送数据功能,至于具体怎么发送数据,WinSock已经帮你封装好了这种功能。
2、TCP/IP协议介绍
TCP/IP协议包含的范围非常的广,他是一种四层协议,包含了各种硬件、软件需求的定义。 TCP/IP协议确切的说法应该
是TCP/UDP/IP协议。
UDP协议( 用户数据报协议),是一种保护消息边界的,不保障可靠数据的传输。
TCP协议(传输控制协议),是一种流传输的协议。他提供可靠的、有序的、双向的、面向连接的传输。
保护消息边界,就是指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息。也就是说存在保护消息边界,接收端一次只能接收发送端发出的一个数据包。而面向流则是指无保护消息保护边界的,如果发送端连续发送数据,接收端有可能在一次接收动作中,会接收两个或者更多的数据包。
举例来说,假如,我们连续发送三个数据包,大小分别是2k、4k、8k,这三个数据包都已经到达了接收端的网络堆栈中,如果使用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有三次接收动作,才能够把所有的数据包接收完。而使用TCP协议,我们只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的数据包接收下来,只需要有一次接收动作。
这就是因为UDP协议的保护消息边界使得每一个消息都是独立的。而流传输,却把数据当作一串数据流,它不认为数据是一个一个的消息。所以有很多人在使用TCP协议通讯的时候,并不清楚TCP是基于流的传输,当连续发送数据的时候,他们时常会认识TCP会丢包。其实不然,因为当他们使用的缓冲区足够大时,他们有可能会一次接收到两个甚至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个数据包,而已经接收的其他据包却被忽略了。
3.WinSock编程简单流程
WinSock编程分为服务器端和客户端两部分,TCP服务器端的大体流程如下:
对于任何基于WinSock的编程首先必须要初始化WinSock DLL库。
int WSAStarup( WORD wVersionRequested,LPWSADATA lpWsAData )。
wVersionRequested是我们要求使用的WinSock的版本。
SOCKET Socket(int af,int type,int protocol);
套接字可以说是WinSock通讯的核心。WinSock通讯的所有数据传输,都是通过套接字来完成的,套接字包含了两个信息,一个是IP地址,一个是Port端口号,使用这两个信息,就可以确定网络中的任何一个通讯节点。
int bind(SOCKET s,const struct sockaddr FAR* name,int namelen) ;
struct sockaddr_in{
short sin_family ;
u_short sin_prot ;
struct in_addr sin_addr ;
char sin_sero[8] ;
}
就包含了需要建立连接的本地的地址,包括地址族、IP和端口信息。sin_family字段必须把它设为AF_INET,这是告诉WinSock使用的是IP地址族。sin_prot就是要用来通讯的端口号。sin_addr就是要用来通讯的IP地址信息。
在这里,必须还得提一下有关'大头(big-endian)'小头(little-endian)'。因为各种不同的计算机处理数据时的方法是不一样的,Intel X86处理器上是用'小头'形式来表示多字节的编号,就是把低字节放在前面,把高字节放在后面,而互联网标准却正好相反,所以,必须把主机字节转换成网络字节的顺序。WinSock API提供了几个函数。
把主机字节转化成网络字节的函数;
u_long htonl(u_long hostlong);
u_short htons(u_short hostshort);
把网络字节转化成主机字节的函数;
u_long ntohl(u_long netlong);
u_short ntohs(u_short netshort) ;
这样,设置IP地址和port端口时,就必须把主机字节转化成网络字节后,才能用Bind()函数来绑定套接字和地址。
当绑定完成之后,服务器端必须建立一个监听的队列来接收客户端的连接请求。
int listen(SOCKET s,int backlog);
这个函数可以把套接字转成监听模式。
如果客户端有了连接请求,我们还必须使用
int accept(SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen);
来接受客户端的请求。
现在基本上已经完成了一个服务器的建立,而客户端的建立的流程则是初始化WinSock,然后创建Socket套接字,再使用
int connect(SOCKET s,const struct sockaddr FAR* name,int namelen) ;来连接服务端。
服务器端的创建:
WSADATA wsd;
SOCKET sListen;
SOCKET sclient;
UINT port = 800;
int iAddrSize;
struct sockaddr_in local , client;
WSAStartup( 0x11 , &wsd );
sListen = Socket ( AF_INET , SOCK_STREAM , IPPOTO_IP );
local.sin_family = AF_INET;
local.sin_addr = htonl( INADDR_ANY );
local.sin_port = htons( port );
bind( sListen , (struct sockaddr*)&local , sizeof( local ) );
listen( sListen , 5 );
sClient = accept( sListen , (struct sockaddr*)&client , &iAddrSize );
WSADATA wsd;
SOCKET sClient;
UINT port = 800;
char szIp[] = "127.0.0.1";
int iAddrSize;
struct sockaddr_in server;
WSAStartup( 0x11 , &wsd );
sClient = Socket ( AF_INET , SOCK_STREAM , IPPOTO_IP );
server.sin_family = AF_INET;
server.sin_addr = inet_addr( szIp );
server.sin_port = htons( port );
connect( sClient , (struct sockaddr*)&server , sizeof( server ) );
int send( SOCKET s,const char FAR* buf,int len,int flags);
int recv( SOCKET s,char FAR* buf,int len,int flags);
函数来接收和发送数据,因为,TCP连接是双向的。
int shutdown(SOCKET s,int how);
来关闭套接字的指定功能,再调用
int closeSocket(SOCKET s) ;
来关闭套接字句柄,这样一个通讯过程就算完成了。
注意:上面的代码没有任何检查函数返回值,如果你作网络编程就一定要检查任何一个WinSock API函数的调用结果,因为很多时候函数调用并不一定成功。上面介绍的函数,返回值类型是int的话,如果函数调用失败的话,返回的都是SOCKET_ERROR。
上面介绍的仅仅是最简单的WinSock通讯的方法,而实际中很多网络通讯的却很多难以解决的意外情况。
例如,WinSock提供了两种套接字模式:锁定和非锁定。
当使用锁定套接字的时候,使用的很多函数,例如accpet、send、recv等等,如果没有数据需要处理,这些函数都不会返回,也就是说,你的应用程序会阻塞在那些函数的调用处。而如果使用非阻塞模式,调用这些函数,不管你有没有数据到达,他都会返回。所以有可能我们在非阻塞模式里,调用这些函数大部分的情况下会返回失败,所以就需要我们来处理很多的意外出错。
这显然不是我们想要看到的情况。我们可以采用WinSock的通讯模型来避免这些情况的发生。
WinSock提供了五种套接字I/O模型来解决这些问题。他们分别是select(选择),WSAAsyncSelect(异步选择),WSAEventSelect (事件选择,overlapped(重叠), completion port(完成端口)。
这里详细介绍一下select,WSAASyncSelect两种模型。
Select模型是最常见的I/O模型。使用
int select( int nfds , fd_set FAR* readfds , fd_set FAR* writefds,fd_set FAR*exceptfds,const struct timeval FAR * timeout ) ;
函数来检查你要调用的Socket套接字是否已经有了需要处理的数据。
select包含三个Socket队列,分别代表:
readfds ,检查可读性,writefds,检查可写性,exceptfds,例外数据。
timeout是select函数的返回时间。
WinSock提供了一些宏用来操作套接字队列fd_set。
FD_CLR( s,*set)从队列set删除句柄s。
FD_ISSET( s, *set) 检查句柄s是否存在与队列set中。
FD_SET( s,*set )把句柄s添加到队列set中。
FD_ZERO( *set ) 把set队列初始化成空队列。
WSAAsyncSelect(异步选择)模型:
WSAASyncSelect模型就是把一个窗口和套接字句柄建立起连接,套接字的网络事件发生时时候,就会把某个消息发送到窗口,然后可以在窗口的消息响应函数中处理数据的接收和发送。
int WSAAsyncSelect( SOCKET s, HWND hWnd , unsigned int wMsg , long lEvent ) ;
这个函数可以把套接字句柄和窗口建立起连接,
wMsg 是我们必须自定义的一个消息。
lEvent就是制定的网络事件。包括FD_READ , FD_WRITE ,FD_ACCEPT,FD_CONNECT,FD_CLOSE。几个事件。
例如,需要接收FD_READ , FD_WRITE, FD_CLOSE的网络事件。可以调用
WSAAsyncSelect( s , hWnd , WM_SOCKET , FD_READ | FD_WRITE | FD_CLOSE ) ;
这样,当有FD_READ, FD_WRITE或者 FD_CLOSE网络事件时,窗口hWnd将会收到WM_SOCKET消息,消息参数的lParam标志了是什么事件发生,MFC的CSocket类,就是使用这个模型。