收藏 分销(赏)

人力资源-linux培训资料.docx

上传人:xrp****65 文档编号:8458575 上传时间:2025-02-14 格式:DOCX 页数:22 大小:32.61KB
下载 相关 举报
人力资源-linux培训资料.docx_第1页
第1页 / 共22页
人力资源-linux培训资料.docx_第2页
第2页 / 共22页
点击查看更多>>
资源描述
新人培训阶段学习资料 上海核心信息技术有限公司 Version 0.02 (2011.03) 目录 课程介绍 1 课程大纲 2 第一阶段 Linux开发基础 2 第二阶段 嵌入式C语言编程强化 3 第三阶段 Linux用户态开发 8 第四阶段 Linux内核态及驱动开发 10 第五阶段 软件开发流程 11 课程介绍 本课程旨在发现具备开发Linux下驱动程序的人才,新入社员将通过一个月的时间参照本教程熟悉Linux下设备驱动开发必须的知识。培训结束后符合要求的新人将进入公司具体项目组熟悉具体项目的开发方法。 课程大纲 本课程大纲内列出的任务基本由员工自己动手解决为主,通常每天上午指导人员将进行昨日实验结果评价及当日任务安排,对于工作任务不清楚的地方请及时向指导人员提出。下午主要为新员工个人实验时间。 第一阶段 Linux开发基础 2-3天 通过本课程的学习,使新员工能够了解Linux操作系统的概念,熟练掌握Linux下的基本命令、常用工具的使用方面的知识。 学习内容: ◆ 公司安全保密教育,日报格式说明 ◆ Linux常用命令,文本编辑器Vi,简单Shell脚本编程 ◆ 嵌入式Linux开发环境基础:Gcc,Gdb,Make和Makefile GCC ARM编译环境安装(Sourcery G++ Lite Edition for ARM) ◆ 软件版本管理器Svn ◆ 嵌入式软件开发环境搭建与使用 x86 linux内核编译 versatile arm linux内核编译 QEMU运行linux 实验: 开发环境配置,安装ubuntu虚拟机,熟悉Linux使用 配置X86开发环境,编译x86 Linux内核,在QEMU下运行 配置ARM开发环境,编译arm Linux内核,在QEMU下运行 编写Hello World程序,在x86/arm Linux QEMU下运行 编写一个脚本,统计一个目录下面所有C代码的行数。 这些格式的如何去解压 .tar/bz2/tar.bz2/tar.gz/tar.tar/.Z/.zip/.rar 第二阶段 嵌入式C语言编程强化 3-5天 本课程的主要目标是通过编写代码的方式,加强对于C语言编程和数据结构的掌握程度。 回答如下16道国外经典的面向嵌入式C语言面试题 1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) 2. 写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。 3. 预处理器标识#error的目的是什么? 4. 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢? 5. 用变量a给出下面的定义 a) 一个整型数(An integer) b) 一个指向整型数的指针(A pointer to an integer) c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer) d) 一个有10个整型数的数组(An array of 10 integers) e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer) h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer ) 6. 关键字static的作用是什么? 7.关键字const是什么含意? 8. 关键字volatile有什么含意 并给出三个不同的例子。 9. 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。 10. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。 11. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具体所代表的事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。 __interrupt double compute_area (double radius) { double area = PI * radius * radius; printf(" Area = %f", area); return area; } 12 . 下面的代码输出是什么,为什么? void foo(void) { unsigned int a = 6; int b = -20; (a+b > 6) puts("> 6") : puts("<= 6"); } 13. 评价下面的代码片断: unsigned int zero = 0; unsigned int compzero = 0xFFFF; /*1's complement of zero */ 不具备可移植性性 14. 尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么? char *ptr; if ((ptr = (char *)malloc(0)) == NULL) puts("Got a null pointer"); //1 else puts("Got a valid pointer"); //2 输出2 这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是 P.J. Plauger, 他的解释远远超过我这里能提到的任何解释),所有回过头看一下这些杂志吧! 。。。。free 这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是“Got a valid pointer”。我用这个来开始讨论这样的一问题,看看被面试者是否想到库例程这样做是正确。 15. Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子: #define dPS struct s * typedef struct s * tPS; 以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么? 16. C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么? int a = 5, b = 7, c; c = a+++b; 12 编程题 ◆ 位操作练习 Description 假设你工作在一个32位的机器上,你需要将某一个外设寄存器的第X位设置成0(最低位为第0位,最高位为第31位),将第Y位开始的连续三位设置成110(从高位到低位的顺序),而其他位保持不变。对给定的寄存器值R,及X,Y,编程计算更改后的寄存器值R。 Input 仅一行,包括R,X,Y,以逗号","分隔,R为16进制表示的32位整数,X,Y在0-31之间且Y>=3,(Y-X)的绝对值>=3,保证两次置位不会重合 Output 更改后的寄存器值R(16进制输出) Sample Input 12345678,0,3 Sample Output 1234567c void main() { int R,X,Y; scanf("%d,%d,%d",&R,&X,&Y); R&=~(1<<X); R|=6<<(Y-3); R&=~(1<<(Y-2)); printf("the R value is %d",R); } ◆ 排序 编写一个排序程序。被排序的文件有8MB大小,一行一个随机整数(ASCII格式)。要求对这些整数进行排序,并计算平均值,打印出排序所需的时间。 #include "stdio.h" #include "stdlib.h" #include "math.h" #include "time.h" void run(int* pData,int left,int right) { int i,j; int middle,iTemp; i = left; j = right; middle = pData[left]; do{ while((pData[i]<middle) && (i<right)) i++; while((pData[j]>middle) && (j>left)) j--; if(i<=j) { iTemp = pData[i]; pData[i] = pData[j]; pData[j] = iTemp; i++; j--; } }while(i<=j); if(left<j) run(pData,left,j); if(right>i) run(pData,i,right); } void QuickSort(int* pData,long Count) { run(pData,0,Count-1); } int main(int argc, char* argv[]) { clock_t start,end; // time_t a,b; char fstr[20]; int m_data[1024]; long count=0; long sum=0; long avr; long i; FILE* m_file; if(NULL== argv[0]) { exit(1); } m_file=fopen(argv[0] , "r"); if(m_file==NULL) { printf("error"); exit(1); } while(NULL!=fgets(fstr,20,m_file)) { m_data[count]=atoi(fstr); count++; } start=clock(); // a=time(NULL); QuickSort(m_data,count); end=clock(); printf(" %6.3f seconds\n",(double)(end-start)/18.2); //b=time(NULL); for(i=0;i<count;i++) { printf("\n%d",m_data[i]); sum+=m_data[i]; } avr=sum/count; ◆ 建立单向、双向、循环链表,进行相应操作   struct Node{   int data;//数据域   struct Node * next;//指针域   }; 单向: struct Node { int data; struct Node* next; }; struct Node* Create_Node(int n)//Create a Node, n means it has n child node; { struct Node* p=(struct Node*)malloc(sizeof(Node));//Create a memory space for struct memset(p,NULL,sizeof(Node));//set the struct’s value NULL; if(n>1) { p->next=Create_Node(n-1);//if the node has child ,then make the p’s next link the next node } return p;//return the node’s address } void Delete_Node(struct Node * node)//free the all node tables { if(node->next!=NULL) { Delete_Node(node->next); } node->next=NULL; free(node); } 双向: struct MuNode { int data; struct MuNode* pre;// Pointer to point to previous node struct MuNode* next; // Pointer to point to next node }; struct MuNode* Create_MuNode(int n,struct MuNode* pre) { struct MuNode* p=(struct MuNode*)malloc(sizeof(Node)); memset(p,NULL,sizeof(Node)); p->pre=pre; if(n>1) { p->next=Create_MuNode(n-1,p); } return p; } void Delete_MuNode(struct MuNode * node) { if(node->next!=NULL) { Delete_MuNode(node->next); } node->next=NULL; node->pre=NULL; free(node); } 循环链表   struct Node{   int data;//数据域   struct Node * next;//指针域   }; struct Node* Create_CycleNode(int n, struct Node* head)//Create a Node, n means it has n child node; { struct Node* p=(struct Node*)malloc(sizeof(Node));//Create a memory space for struct memset(p,NULL,sizeof(Node));//set the struct’s value NULL; if(n>1) { p->next=Create_Node(n-1);//if the node has child ,then make the p’s next link the next node } else { p->next=head; } return p;//return the node’s address } void Delete_CycleNode(struct Node * node, struct Node * head) { if(node->next!=head) { Delete_Node(node->next); } node->next=NULL; free(node); } ◆ 队列基本操作(入队,出队) 循环队列类型定义   #define QueueSize 100 //应根据具体情况定义该值   typedef char DataType; //DataType的类型依赖于具体的应用   typedef struct{   int front; //头指针,队非空时指向队头元素   int rear; //尾指针,队非空时指向队尾元素的下一位置   int count;//计数器,记录队中元素总数   DataType data[QueueSize];   }CirQueue; void InitQueue(CirQueue *Q) //初始化队列 { Q->front=0; Q->count=0; Q->rear=0; } int QueueEmpty(CirQueue *Q) { return (Q->count==0) } int QueueFull(CirQueue *Q) { return (Q->count== QueueSize); } void EnQueue(CirQueuq *Q,DataType x) { if(!QueueFull(CirQueue *Q)) { Q->data[Q->rear]= x; Q->rear=(Q->rear+1)%QueueSize; Q->count++; } else { error("The Queue is Full! now!\n"); } } DataType DeQueue(CirQueue *Q) {  DataType temp; if(QueueEmpty((Q)) Error("Queue underflow")//队空下溢 temp=Q->data[Q->front]; Q->count--; //队列元素个数减1    Q->front=(Q->front+1)%QueueSize; //循环意义下的头指针加1   return temp; } DataType QueueFront(CirQueue *Q) { if(!QueueEmpty) return Q[Q->front]; else { error("Queue is empty"); } } ◆ 栈基本操作(入栈,出栈)   #define DataType int   #define MAXSIZE 1024   typedef struct   {   DataType data[MAXSIZE];   int top;   }SeqStack; SeqStack *Init_SeqStack()//栈初始化 { SeqStack *p= (SeqStack *)malloc(sizeof(SeqStack)); memset(p,NULL,sizeof(SeqStack)); return p; } int Empty_SeqStack(SeqStack *s)//判栈空 { return (s->top==0); } int Push_SeqStack(SeqStack *s,DataType x)//入栈 { if(s->top< MAXSIZE) { s->data[s->top]=x; return 1 } else return 0; } int Pop_SeqStack(SeqStack *s,DataType *x)//出栈 { if(s->top>0) { *x=s->data[s->top]; s->top--; return 1; } else return 0; } DataType Top_SeqStack(SeqStack *s)//取栈顶元素 { if(s->top>0) return s->data[s->top]; else error("Stack is empty"); } ◆ 其他 编写一个自己的完全C语言版本的memset函数,并且评价这个实现的性能和可移植性。 void* memset(void * source, int ch, unsigned n);) { char *p=(char*) source; assert(NULL!=source); while(n--) { *p++=(char)c; } return source; } ◆ 代码风格 下面是一个16x16的黑白图标: static unsigned short stopwatch【】 = { 0x07c6, 0x1ff7, 0x383b, 0x600c, 0x600c, 0xc006, 0xc006, 0xdf06, 0xc106, 0xc106, 0x610c, 0x610c, 0x3838, 0x1ff0, 0x07c0, 0x0000, }; 如何修改声明,可以使之在源代码中形象地表现出图形的模样 //C编程专家 #define X )*2+1 #define _ )*2 #define s ((((((((((((((((0 static unsigned short stopwatch[]= { s _ _ _ _ _ X X X X X _ _ _ X X _, s _ _ _ X X X X X X X X X _ X X X, s _ _ X X X _ _ _ _ _ X X X _ X X, s _ X X _ _ _ _ _ _ _ _ X X X _ _, s _ X X _ _ _ _ _ _ _ _ X X X _ _, s X X _ _ _ _ _ _ _ _ _ _ _ X X _, s X X _ _ _ _ _ _ _ _ _ _ _ X X _, s X X _ X X X X X _ _ _ _ _ X X _, s X X _ _ _ _ _ X _ _ _ _ _ X X _, s X X _ _ _ _ _ X _ _ _ _ _ X X _, s _ X X _ _ _ _ X _ _ _ _ X X _ _, s _ X X _ _ _ _ X _ _ _ _ X X _ _, s _ _ X X X _ _ _ _ _ X X X _ _ _, s _ _ _ X X X X X X X X X _ _ _ _, s _ _ _ _ _ X X X X X _ _ _ _ _ _, s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _, }; 第三阶段 Linux用户态开发 5天左右 熟悉Linux用户态开发的基本概念,通过编写一些实验程序加深理解。 用户态编程学习内容 系统调用方式访问文件 库函数访问文件 时间编程 进程原理 进程控制程序设计 进程间通讯 管道 信号 共享内存 消息队列 信号量 多线程程序设计 socket编程(TCP, UDP) Linux用户态编程实验内容: 编写应用程序,创建一个可读可写的文件。 程序名:CreateFile #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> void create_file(char *filename){ if(creat(filename,0755)<0){ printf("create file %s failure!\n",filename); exit(EXIT_FAILURE); }else{ printf("create file %s success!\n",filename); } } int main(int argc,char *argv[]){ int i; if(argc<2){ perror("you haven't input the filename,please try again!\n"); exit(EXIT_FAILURE); } for(i=1;i<argc;i++){ create_file(argv[i]); } exit(EXIT_SUCCESS); } 执行命令:gcc CreateFile –o CreateFile ./CreateFile 使用库函数,实现文件拷贝的功能 获取本地时间,以字符串方式显示 编写一应用程序,在程序中创建一子进程,分别在父进程和子进程中打印进程ID 使用vfork创建一子进程,分别在父进程和子进程中打印进程ID,观察父子进程的运行顺序 使用execl函数创建一个文件 编写一应用程序,在程序中创建一子进程,父进程需等待子进程运行结束后才能执行 在父进程中创建一个无名管道,并创建子进程来读该管道,父进程来写该管道 启动A进程,创建一有名管道,并向其写入一些数据;启动B进程,从A创建的有名管道中读出数据 在进程中为SIGBUS注册处理函数,并向该进程发送SIGBUS信号 启动A进程,创建一共享内存,并向其写入一些数据;启动B进程,从A创建的共享内存中读出数据 创建一消息队列,实现向队列中存放数据和读取数据 编写应用程序,创建一线程,并向该线程处理函数传递一结构 编写应用程序,创建一线程,父进程需要等待该线程结束后才能继续执行 编写应用程序,创建一线程,使用pthread_cleanup_push和pthread_cleanup_pop进行退出保护 编写使用TCP协议的服务器程序;编写使用TCP协议的客户端程序; 客户端向服务器发送字符串,服务器打印收到的字符串 编写使用UDP协议的服务器程序;编写使用UDP协议的客户端程序; 客户端向服务器发送字符串,服务器打印收到的字符串 第四阶段 Linux内核态及驱动开发 5天左右 熟悉Linux内核态和驱动开发的基本概念,通过编写一些实验程序加深理解。 学习内容: 进程地址空间 内核地址空间 Linux内核链表 Linux内核定时器 Linux系统调用 Proc文件系统 内核异常分析 字符设备驱动 驱动中的竞争与互斥 ioctl设备控制 内核等待队列 阻塞形字符设备驱动 poll设备方法 实验: 编写内核模块,在模块中使用kmalloc分配内存并访问 编写内核模块,在模块中使用页方式分配内存并访问 编写内核模块,在模块中创建一链表,遍历该链表,删除链表中的结点 编写内核模块,在模块中启动一定时器,5秒钟超时,超时后任意打印一条信息 修改内核,在内核中增加一个实现乘法的系统调用,编写应用程序,使用该系统调用 编写内核模块,实现一可读可写的Proc文件 编写实现了读写,定位功能的字符设备驱动程序;编写应用程序,测试驱动 基于上述驱动程序,加入竞争控制 基于上述驱动程序,加入ioctl的支持;设计应用程序,测试ioctl功能 基于上述驱动程序,进行读写改造,将读写实现成阻塞方式 基于上述驱动程序,添加poll设备方法;设计应用程序,测试驱动程序的poll操作 第五阶段 软件开发流程 3天左右 本课程阶段熟悉软件开发通用流程,机能设计、概要设计、详细设计、单体测试、结合测试、集成测试。熟悉类图,交互图,状态图。
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传
相似文档                                   自信AI助手自信AI助手

当前位置:首页 > 教育专区 > 职业教育

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服