已经近两个月了,不能说所教知识都掌握得非常好,但至少还是能跟着老师步伐、理解关键知识点、正确完成作业的。现在还没真正开始进入硬件方面的学习,但我相信对基本理论知识及编程开发的牢固掌握是后续深入学习的前提。因此,趁着现在正处与学习进度的转折点,有必要对先前的知识作一下概括性总结。 ★Linux的使用 开班的第一天,老师就给我们讲了为什么要先学c、学linux:因为嵌入式的根本就是软件驱动硬件,而C语言是最接近硬件的语言、有指针的概念、可以直接操作硬件,另外,功能复杂的硬件是含有操作系统的,这就需要我们选择使用广泛而开源的linux来学习。 ◇Shell 命令 shell是一个命令行解释器,命令行格式为:命令名称、选项、参数,常用的命令有:cd进入目录;ls显示目录下的文件;touch、mkdir创建文件、文件夹;mv、cp、rm移动、复制、删除文件和文件夹;zip、gzip、tar压缩和解压文件;ln创建软硬链接文件。 ◇文件管理、用户管理 Linux是一个多用户系统,它可以用adduser来创建多个用户,并用su来进行不同用户及用户与管理员之间的切换;另外,与目录结构属于分区的windows不同,在Linux的文件系统中,分区属于目录结构。 ◇软件管理 ubuntu上的软件包管理工具apt可以通过网络很方便地完成软件包的获取、安装、卸载、查询等操作。比如,当我们在使用putty前需要安装SSH的时候,就可以通过命令:sudo apt-get update、sudo apt-get install SSH 来安装。 ◇VI 编辑器,GCC 编译器 Vi是Linux系统中常用的一个文本编辑器,通过vi加上文件名可以对文件创建或编辑。三种模式中:命令模式是我们进入编辑器的第一模式,可以对文本进行剪切复制替换删除操作;输入模式可以是对文件进行常规编辑;底行模式可以保存文本并退出。vi编辑好的c文件需要被编译二进制文件才可以被机器识别运行,而GCC 编译器就承载着这样的功能,它通过预处理、编译、汇编、链接四个步骤完成该操作。 ★C语言编程 C语言学习的开始就是掌握基本的语法规则,主要包括各种基本类型常量变量、运算符、控制流、函数的使用。这部分总的来说没有什么难度,但有一些容易忽略的细节需要留意,如同为单目运算的*解引用和++操作同时使用时哪个优先运算;数组被定义后其空间大小和首地址不允许改变;要用strcmp()判断字符串相等而不能直接用==;指针定义后但没初始化会变成野指针,后续使用可能发生段错误;使用较大的数据时应在堆中开辟空间存放以防栈溢出。 ☆数据结构 数据结构就是对数据进行人为的格式化规范化储存,使得数据能够快捷地增删查改,不同的数据结构有不同的优缺点及主要用途,如顺序表查找快增删慢而链表查找满增删快。鉴于内核链表的重要性及以后使用的广泛性,在此只做内核链表的总结。内核链表和双向循环链表类似,与之不同的是,内核链表将数据和链表剥离开,并提供了很多的宏和封装函数。其中非常重要的是list_for_each()、list_entry(),它们分别实现了对小结构体(循环链表)的遍历操作、通过小结构体的地址反推找到大结构体的地址,从而通过大结构体得到其下的数据域。另外还有list_add()、list_del_init()封装实现了对大结构体节点的插入、孤立删除,不然自己搭建双向循环链表的话,就需在头插node节点时要写上经典的四句指针域重连接指令:①node->next = head->next;②head->next->pre = node;③node->pre = head;④head->next = node; ☆文件IO 这里的iO指的是内存和磁盘间的文件交互,由于linux“一切皆文件的”的特性,其7种类型的文件都是可以被输入输出的。其间我们重点学习了文件IO和标准IO,他们的主要区别就是前者直接调用系统函数没有缓冲区,而后者调用的是封装好的库函数有缓冲区。一般来说,文件IO是专门给文件使用的,而标准IO是专门给设备使用的。文件、标准io的打开和关闭所用的函数是相似的,只是一个有f一个没f;但他们的读写函数差别就比较大了,文件io用的是read()、write(),而标准IO根据输入输出是否格式化分为printf、put、scanf、get,具体还会根据一字一行一块地读写及读写目标地的不同而有所不同。另外还了解了下利用time()、ctime()来获取标准时间并转化为可阅读化时间的时间编程,以及通过lstat()、opendir()、readdir()来查看目录下的文件属性。最后介绍了动静态库的概念及制作,前者在文件运行时才加载到可执行文件中,而后者在编译时即完成,至于二者制作步骤的话比较复杂,需要用到的时候再对照着笔记制作好了。 ☆进程线程 这部分我想是重中之重,毕竟进程线程出现的一大动机就跟人类的无限欲望相关联:想要在越短的时间做越多的事情。进程就是执行中的程序,但与只包含指令和数据的程序不同,进程有属于自己的地址空间,里面不仅含有指令段数据段,还有动态的堆栈段,因此多个进程可以实现了同一时间做多个任务。进程通过fork()函数创建,对应的PCB由内核创建并保存在内核空间。尽管多核芯片的出现可以让多个进程真的在同时执行任务,但不是所有进程都同时处于运行状态的,更多的进程是在极小的时间片段下轮流替换着来工作,至于替换的顺序是由cpu调度机制决定的,我们无法确定,这也是为什么进程拥有异步特性的原因。未在运行状态的进程往往处于队列就绪等待状态或休眠状态,其它具体的状态可以通过命令ps -aux查看。此外,运行中的进程还分为前台运行和后台运行,如果进程是后台运行的话,就不能对它进行前台操作,如不能对它ctrl + c暂停,这时候可以通过fg指令把它转变为前台运行或直接用kill指令终止进程。被创建后的进程是有生命周期的,它不但可以exit()自行终止进程,还可以用exec函数族中途改为执行新的进程,殊途同归,进程最后都是要终止的,终止后的进程的PCB需要被其父进程wait()回收,中间有差错的话就可能导致孤儿进程或僵尸进程的出现。 当需要进程不受干扰地一直在后台运行、周期性地等待或者执行某一个任务的时候,可以将它设置为守护进程。守护进程不与任何终端关联,即使终端关闭了也还是会照常运行,老师教的7步创建法得记熟。值得注意的是,因为守护进程无法往标准输出打印,中间出错了也没人知道,所以得找个地方储存它的运行情况,因此系统日志应运而生。系统日志可以通过命令cat /var/log/syslog查看。 进程可以通过无名管道、有名管道、信号、共享内存、消息队列、信号量来进行进程间通信,这些通信方式都是在内核中得以实现的。具体的函数及使用笔记上都有详细记录,就不再赘述了。值得留意的是无名有名管道、消息队列中的同一数据是读了一次就没有了的,而共享内存中的同一数据可以被多次读取。 进程和线程都是为了实现计算机的并发功能,但是进程的创建消亡,及进程间的切换都很耗费资源,每次切换进程都要进程上下文切换。线程的优势是多个线程共享指令和全局变量,这就减少了资源管理的消耗,从而更专注于任务的执行。但有优点就有缺点,资源的共享可能会致使多个线程同时对临界资源进行操作,从而导致运算结果的不准确。为了解决这一问题,出现了线程的互斥与同步。线程互斥利用mutex锁在临界区的前后分别pthread_mutex_lock()上锁和pthread_mutex_destroy()解锁,实现同一时间只允许一个线程操作临界资源。线程的同步用的是信号量,相当于加上了数量的线程的互斥,通过合理地使用p+1、v-1操作使得多个线程按一定次序运行。 以上即为近两个月来重要知识的概括性总结。
|