




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
ARM的嵌入式Linux移植编写Linux应用程序要用到如下工具:(1)编译器:GCCGCC是Linux平台下最重要的开发工具,它是GNU的C和C+编译器,其基本用法为:gcc options filenames。我们应该使用arm-linux-gcc。(2)调试器:GDBgdb是一个用来调试C和C+程序的强力调试器,我们能通过它进行一系列调试工作,包括设置断点、观查变量、单步等。我们应该使用arm-linux-gdb。(3)MakeGNU Make的主要工作是读进一个文本文件,称为makefile。这个文件记录了哪些文件由哪些文件产生,用什么命令来产生。Make依靠此makefile中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话,make就执行相应的命令,以便更新目的文件。Makefile中的编译规则要相应地使用arm-linux-版本。(4)代码编辑可以使用传统的vi编辑器,但最好采用emacs软件,它具备语法高亮、版本控制等附带功能。在宿主机上用上述工具完成应用程序的开发后,可以通过如下途径将程序下载到目标板上运行:(1)通过串口通信协议rz将程序下载到目标板的文件系统中(感谢Linux提供了rz这样的一个命令);(2)通过ftp通信协议从宿主机上的ftp目录里将程序下载到目标板的文件系统中;(3)将程序拷入U盘,在目标机上mountU盘,运行U盘中的程序;(4)如果目标机Linux使用NFS文件系统,则可以直接将程序拷入到宿主机相应的目录内,在目标机Linux中可以直接使用。1. 文件编程Linux的文件操作API涉及到创建、打开、读写和关闭文件。创建int creat(const char *filename, mode_t mode);参数mode指定新建文件的存取权限,它同umask一起决定文件的最终权限(mode&umask),其中umask代表了文件在创建时需要去掉的一些存取权限。umask可通过系统调用umask()来改变:int umask(int newmask);该调用将umask设置为newmask,然后返回旧的umask,它只影响读、写和执行权限。打开int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);读写在文件打开以后,我们才可对文件进行读写了,Linux中提供文件读写的系统调用是read、write函数:int read(int fd, const void *buf, size_t length);int write(int fd, const void *buf, size_t length);其中参数buf为指向缓冲区的指针,length为缓冲区的大小(以字节为单位)。函数read()实现从文件描述符fd所指定的文件中读取length个字节到buf所指向的缓冲区中,返回值为实际读取的字节数。函数write实现将把length个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数。以O_CREAT为标志的open实际上实现了文件创建的功能,因此,下面的函数等同creat()函数:int open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);定位对于随机文件,我们可以随机的指定位置读写,使用如下函数进行定位:int lseek(int fd, offset_t offset, int whence);lseek()将文件读写指针相对whence移动offset个字节。操作成功时,返回文件指针相对于文件头的位置。参数whence可使用下述值:SEEK_SET:相对文件开头SEEK_CUR:相对文件读写指针的当前位置SEEK_END:相对文件末尾offset可取负值,例如下述调用可将文件指针相对当前位置向前移动5个字节:lseek(fd, -5, SEEK_CUR);由于lseek函数的返回值为文件指针相对于文件头的位置,因此下列调用的返回值就是文件的长度:lseek(fd, 0, SEEK_END);关闭只要调用close就可以了,其中fd是我们要关闭的文件描述符:int close(int fd);下面我们来编写一个应用程序,在当前目录下创建用户可读写文件example.txt,在其中写入Hello World,关闭文件,再次打开它,读取其中的内容并输出在屏幕上:#include #include #include #include #define LENGTH 100main()int fd, len;char strLENGTH; fd = open(hello.txt, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* 创建并打开文件 */if (fd) write(fd, Hello, Software Weekly, strlen(Hello, software weekly);/* 写入Hello, software weekly字符串 */close(fd);fd = open(hello.txt, O_RDWR);len = read(fd, str, LENGTH); /* 读取文件内容 */strlen = ;printf(%sn, str);close(fd);2. 进程控制/通信编程进程控制中主要涉及到进程的创建、睡眠和退出等,在Linux中主要提供了fork、exec、clone的进程创建方法,sleep的进程睡眠和exit的进程退出调用,另外Linux还提供了父进程等待子进程结束的系统调用wait。fork对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一,因为它执行一次却返回两个值,以前闻所未闻。先看下面的程序:int main()int i;if (fork() = 0)for (i = 1; i 3; i+)printf(This is child processn);elsefor (i = 1; i );fgets(command, MAX_CMD_LEN, stdin);commandstrlen(command) - 1 = 0;if (fork() = 0)/* 子进程执行此命令 */execlp(command, command);/* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/perror(command);exit(errorno);else/* 父进程,等待子进程结束,并打印子进程的返回值 */wait(&rtn);printf( child process return %dn, rtn);这个函数实现了一个shell的功能,它读取用户输入的进程名和参数,并启动对应的进程。cloneclone是Linux2.0以后才具备的新功能,它较fork更强(可认为fork是clone要实现的一部分),可以使得创建的子进程共享父进程的资源,并且要使用此函数必须在编译内核时设置clone_actually_works_ok选项。clone函数的原型为:int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);此函数返回创建进程的PID,函数中的flags标志用于设置创建子进程时的相关选项。来看下面的例子:int variable, fd;int do_something() variable = 42;close(fd);_exit(0);int main(int argc, char *argv) void *child_stack;char tempch;variable = 9;fd = open(test.file, O_RDONLY);child_stack = (void *) malloc(16384);printf(The variable was %dn, variable);clone(do_something, child_stack, CLONE_VM|CLONE_FILES, NULL);sleep(1); /* 延时以便子进程完成关闭文件操作、修改变量*/printf(The variable is now %dn, variable);if (read(fd, &tempch, 1) 1) perror(File Read Error);exit(1);printf(We could read from the filen);return 0;运行输出:The variable is now 42File Read Error程序的输出结果告诉我们,子进程将文件关闭并将变量修改(调用clone时用到的CLONE_VM、CLONE_FILES标志将使得变量和文件描述符表被共享),父进程随即就感觉到了,这就是clone的特点。sleep函数调用sleep可以用来使进程挂起指定的秒数,该函数的原型为:unsigned int sleep(unsigned int seconds);该函数调用使得进程挂起一个指定的时间,如果指定挂起的时间到了,该调用返回0;如果该函数调用被信号所打断,则返回剩余挂起的时间数(指定的时间减去已经挂起的时间)。exit系统调用exit的功能是终止本进程,其函数原型为:void _exit(int status);_exit会立即终止发出调用的进程,所有属于该进程的文件描述符都关闭。参数status作为退出的状态值返回父进程,在父进程中通过系统调用wait可获得此值。 waitwait系统调用包括:pid_t wait(int *status);pid_t waitpid(pid_t pid, int *status, int options);wait的作用为发出调用的进程只要有子进程,就睡眠到它们中的一个终止为止; waitpid等待由参数pid指定的子进程退出。Linux的进程间通信(IPC,InterProcess Communication)通信方法有管道、消息队列、共享内存、信号量、套接口等。套接字通信并不为Linux所专有,在所有提供了TCP/IP协议栈的操作系统中几乎都提供了socket,而所有这样操作系统,对套接字的编程方法几乎是完全一样的。管道分为有名管道和无名管道,无名管道只能用于亲属进程之间的通信,而有名管道则可用于无亲属关系的进程之间;消息队列用于运行于同一台机器上的进程间通信,与管道相似;共享内存通常由一个进程创建,其余进程对这块内存区进行读写;信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。 下面是一个使用信号量的例子,该程序创建一个特定的IPC结构的关键字和一个信号量,建立此信号量的索引,修改索引指向的信号量的值,最后清除信号量:#include #include #include #include void main()key_t unique_key; /* 定义一个IPC关键字*/int id;struct sembuf lock_it;union semun options;int i;unique_key = ftok(., a); /* 生成关键字,字符a是一个随机种子*/* 创建一个新的信号量集合*/id = semget(unique_key, 1, IPC_CREAT | IPC_EXCL | 0666);printf(semaphore id=%dn, id);options.val = 1; /*设置变量值*/semctl(id, 0, SETVAL, options); /*设置索引0的信号量*/*打印出信号量的值*/i = semctl(id, 0, GETVAL, 0);printf(value of semaphore at index 0 is %dn, i);/*下面重新设置信号量*/lock_it.sem_num = 0; /*设置哪个信号量*/lock_it.sem_op = - 1; /*定义操作*/lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/if (semop(id, &lock_it, 1) = - 1)printf(can not lock semaphore.n);exit(1);i = semctl(id, 0, GETVAL, 0);printf(value of semaphore at index 0 is %dn, i);/*清除信号量*/semctl(id, 0, IPC_RMID, 0);3. 线程控制/通信编程Linux本身只有进程的概念,而其所谓的线程本质上在内核里仍然是进程。大家知道,进程是资源分配的单位,同一进程中的多个线程共享该进程的资源(如作为共享内存的全局变量)。Linux中所谓的线程只是在被创建的时候克隆(clone)了父进程的资源,因此,clone出来的进程表现为线程。Linux中最流行的线程机制为LinuxThreads,它实现了一种Posix 1003.1c pthread标准接口。线程之间的通信涉及同步和互斥,互斥体的用法为:pthread_mutex_t mutex;pthread_mutex_init(&mutex, NULL); /按缺省的属性初始化互斥体变量mutexpthread_mutex_lock(&mutex); / 给互斥体变量加锁 /临界资源phtread_mutex_unlock(&mutex); / 给互斥体变量解锁同步就是线程等待某个事件的发生。只有当等待的事件发生线程才继续执行,否则线程挂起并放弃处理器。当多个线程协作时,相互作用的任务必须在一定的条件下同步。Linux下的C语言编程有多种线程同步机制,最典型的是条件变量(condition variable)。而在头文件semaphore.h 中定义的信号量则完成了互斥体和条件变量的封装,按照多线程程序设计中访问控制机制,控制对资源的同步访问,提供程序设计人员更方便的调用接口。下面的生产者/消费者问题说明了Linux线程的控制和通信:#include #include #define BUFFER_SIZE 16 struct prodconsint bufferBUFFER_SIZE;pthread_mutex_t lock;int readpos, writepos; pthread_cond_t notempty;pthread_cond_t notfull;/* 初始化缓冲区结构 */void init(struct prodcons *b)pthread_mutex_init(&b-lock, NULL);pthread_cond_init(&b-notempty, NULL);pthread_cond_init(&b-notfull, NULL);b-readpos = 0;b-writepos = 0;/* 将产品放入缓冲区,这里是存入一个整数*/void put(struct prodcons *b, int data)pthread_mutex_lock(&b-lock);/* 等待缓冲区未满*/if (b-writepos + 1) % BUFFER_SIZE = b-readpos)pthread_cond_wait(&b-notfull, &b-lock);/* 写数据,并移动指针 */b-bufferb-writepos = data;b-writepos+;if (b-writepos = BUFFER_SIZE)b-writepos = 0;/* 设置缓冲区非空的条件变量*/pthread_cond_signal(&b-notempty);pthread_mutex_unlock(&b-lock);/* 从缓冲区中取出整数*/int get(struct prodcons *b)int data;pthread_mutex_lock(&b-lock);/* 等待缓冲区非空*/if (b-writepos = b-readpos)pthread_cond_wait(&b-notempty, &b-lock);/* 读数据,移动读指针*/data = b-bufferb-readpos;b-readpos+;if (b-readpos = BUFFE
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 租赁高端珠宝合同范本
- 自家出售步梯合同范本
- 民间炒股合作合同范本
- 猫粮加工购买合同范本
- 物品翻新修理合同范本
- 通信铁塔拆除合同范本
- 民间借贷的易合同范本
- 广东省汕尾市高中消防安全测试题九(含答案)
- 江苏省南通市电影院消防安全测试题十七(含答案)
- 吉林省四平市小区消防安全测试题二(含答案)
- 智能交通系统建设方案
- 教科版小学科学一年级上册全册教案【全套】
- 成人肠造口护理
- 安徽省宣城市宣州区宣城市第六中学2024-2025学年九年级上学期开学物理试题
- 2024届重庆巴川量子中学毕业升学考试模拟卷数学卷含解析
- 家庭经济困难学生认定申请表
- 世界科学技术史全册配套完整课件
- 金川集团社招考试题
- 合规和法律合规管理制度
- 选择性必修二《Unit 1 Science and Scientists》单元教学设计
- 新手会计上岗实操100问
评论
0/150
提交评论