570 likes | 720 Views
UNIX 基础与开发. 提纲. 如何开发高质量的软件 UNIX 文件系统 UNIX 的 SHELL UNIX 开发与调试 经验分享 讨论. 如何开发高质量的软件 /1. 软件开发 =Coding ? 面试的故事 第一轮: 功能: A 、 B 、 C C 先生: 25 分钟( Coding ) I 先生: 10 (想) +30 ( Coding )分钟 第二轮: 功能: A’ 、 D 、 C C 先生: 10 (改) +25 (重写)分钟 I 先生: 10 (想) +25 ( Coding )分钟 第三轮:
E N D
提纲 • 如何开发高质量的软件 • UNIX文件系统 • UNIX的SHELL • UNIX开发与调试 • 经验分享 • 讨论
如何开发高质量的软件/1 • 软件开发=Coding? • 面试的故事 • 第一轮: • 功能:A、B、C • C先生:25分钟(Coding) • I先生:10(想)+30(Coding)分钟 • 第二轮: • 功能:A’、D、C • C先生:10(改)+25(重写)分钟 • I先生: 10(想)+25(Coding)分钟 • 第三轮: • 功能:A、B、C’、E • C先生:10(改)+?(重写)分钟 • I先生: 10(想)+25(Coding)分钟
如何开发高质量的软件/2 • 软件开发什么最重要? • 编写高质量代码最重要? • 设计最重要? • 需求最重要? • 测试最重要? • 计划最重要?
如何开发高质量的软件/3 • 高质量代码 • 先做设计,再写代码 • 制定编码规范,严格执行 • 代码走查制度 • 每个功能块(类)都要有单元测试代码,对不同的入口参数进行充分测试 • 了解OS原理对编写高质量代码有帮助 • 权衡:性能与可读性、内存与速度、避免过度的编程技巧(除非特殊情况)… • 正确使用内存空间 • 参数合法性检查、通信数据合法性检查 • 作为服务器的程序,要考虑安全性 • … …
如何开发高质量的软件/4 • 软件设计 • 紧扣需求 • 2/8原则:以最原始的方法实现某些复杂的功能 • 形成文档 • 以不变的架构应万变的需求 • 确定框架之前,针对实际的系统做部分关键技术研究,获得实际数据 • 模块化、可扩展、复用性… …
如何开发高质量的软件/5 • 需求分析 • 充分与客户沟通,深入挖掘需求 • 关注隐性需求 • 需求到功能的转换 • 2/8原则:引导客户放弃某些需求,以其他方式代替某些需求
如何开发高质量的软件/6 • 测试(质量保证) • 强调单元测试: • 每个功能块(类)对应一个单元测试程序 • 模拟上下接口 • 每个模块都要建立模拟测试环境 • 不要因为赶工忽略系统测试,不能运用2/8原则 • 稳定性测试 • 性能测试(开发人员配合) • 压力测试
如何开发高质量的软件/7 • 计划 • 对于死亡之旅的项目,倒排计划不失为一种好的方式 • 风险储备 • 测试要占用整个项目1/2的时间,对于死亡之旅的项目,测试至少占用1/3的时间 • 计划的执行和跟踪(自我跟踪)
提纲 • 如何开发高质量的软件 • UNIX文件系统 • UNIX的SHELL • UNIX开发与调试 • 经验分享 • 讨论
UNIX文件系统/1 • 所有的UNIX都是基于文件的 • Solaris的文件系统是UFS • 文件分类: • 普通文件 • 目录文件 • 特殊文件 • 文件是有权限的,文件的权限是与用户的权限相结合来管理的 • 文件的文件主、同组用户、其他用户 • 文件的读-写-执行权限(rwx)
UNIX文件系统/2 • UNIX文件系统的树形结构(Solaris)
UNIX文件系统/3 • 普通文件 • 文件名:255字节长度限制 • 文件路径名:相对路径名、绝对路径名 • 文件名扩展:file.c, file.h • 某些编程语言(C)对文件的扩展名依赖性强 • 大多数情况文件名扩展是可选的 • 隐藏的文件名:.file
UNIX文件系统/4 • 目录文件 • Solaris的重要目录 • / 根目录 • /dev 设备(特殊)文件 • /etc 本地计算机系统配置 • /home 用户目录 • /tmp 临时文件 • /usr 第二个主文件层次结构 • /usr/bin 用户命令 • /usr/sbin 非重要的系统管理二进制文件 • /usr/lib 库文件和现场 • /usr/include 头文件 • /usr/man 手册页 • 执行权限对于目录来说就是搜索的权限,对一个目录要有读和执行权限,才能转移到目录下
UNIX文件系统/5 • 特殊文件 • 设备文件:/dev • 硬盘/硬盘分区 • CDROM、软盘、磁带 • PCI卡(网卡) • … … • 有名管道 • Socket • Proc文件系统: • 虚拟文件系统 • 包含系统和进程的调试信息,对服务器程序的调试很有帮助
提纲 • 如何开发高质量的软件 • UNIX文件系统 • UNIX的SHELL • UNIX开发与调试 • 经验分享 • 讨论
UNIX的SHELL • shell是一种命令解释程序和编程语言 • 运行命令 • 高级语言 • 通用Shell: • Bourne shell(sh/bsh):最初的UNIX shell • C shell(csh):Berkeley UNIX • Korn shell(ksh):综合多个shell特点 • Solaris的默认Shell: • Bourne shell(sh/bsh)
Shell基础/1 • 开始 • 登录 • 图形界面、字符界面、仿真终端、telnet • 注销 • Logout、exit • 超级用户:最好不要用超级用户登录 • 修正错误 • 删除一个字符:BACKSPACE、CONTROL-H、Delete、Del • 删除一个单词:CONTROL-W • 删除一行: CONTROL-U • 终止程序执行:CONTROL-C、CONTROL-Z、Kill -9
Shell基础/2 • 特殊字符 • 支持通配符:*、[0-9] • 特殊字符:& ; | * ? ‘ “ ` [ ] ( ) $ < > { } ^ # / \ % ! ~ + • 引用特殊字符:反斜杠\,如\*\*,或引号“” • 联机帮助:man
Shell命令/1 • 基本实用命令 • ls:列出某个目录下的内容 • cat:显示一个文本文件 • pg、more:显示一个长文本文件 • rm:删除一个文件 • hostname:显示计算机名 • echo:显示文本 • date:显示时间和日期 • script:记录一个Solaris会话
Shell命令/2 • 文件和目录基本处理 • cp:复制文件 • mv:更改文件名 • grep:查找一个字符串 • head:显示文件开始 • tail:显示文件结尾 • Sort:按次序显示文件(不会改变文件的内容) • uniq:删除文件中的重复行 • diif:比较两个文件 • file:测试文件的内容 • mkdir:创建一个目录 • cd:更换到其他工作目录 • pwd:显示工作目录的路径名 • rmdir:删除一个目录(必须是空目录) • mv:移动一个目录或文件 • rm:删除一个文件,或目录及其下的所有文件
Shell命令/3 • 文件的权限 • ls –l能列出文件或目录的权限 • chmod:更改访问权限 chmod g+w file1 • setuid和setgid权限 chmod s+w program • 减少s e t u i d和s e t g i d程序的使用 • 不要编写setuid的shell脚本 • 目录的权限 • 读权限:能列出目录下的文件 • 写权限:能在目录下信件文件 • 执行权限:能转移到目录的子目录下
Shell命令/4 • 文件的连接 • ln:创建一个连接 • ln /home/jenny/draft /home/alex/letter • 与cp的区别:文件副本的个数,连接是一个文件副本,cp有两个文件副本 • 符号连接与硬连接:符号连接的文件副本可以不存在 • 连接的删除:rm
Shell命令/5 • 文件的压缩和存档 • compress:压缩文件 • uncompress、zcat:扩展文件 • tar:打包和解包某个文件
Shell命令/6 • 网络命令 • ping:测试网络连接 • rlogin、telnet、ssh:访问某个远程计算机 • rcp、ftp:通过网络传输文件 • rsh:远程运行一个命令 • 文件系统 • newfs:新建一个文件系统 • fsck:检查文件系统 • mount/umount:安装/反安装一个文件系统
Shell命令/7 • 其他命令 • which、whereis:查找命令的位置 • ps:查看系统进程的信息 • top:查看系统性能 • who、w、finger:列出系统上的用户名单 • write、talk:向其他用户发送消息、通信 • mesg:拒绝或接受消息
Shell命令/8 • Vi编辑器 • 启动vi • vi file • 两种操作模式 • 命令模式 • 输入模式 • 结束Vi • :q!, :wq!, ZZ • 命令区分大小写 • 撤销命令的执行:u
Shell命令/9 • Vi编辑器 • 命令模式 • 光标移动 • 换屏 • 删除字符:x • 删除一行或多行:dd、Xdd • 从vi执行shell命令::sh, :!cmd(:!pwd) • 读取文件::[address]r[filename] • 写入文件: :[address]w[!][filename] • 到文件尾::$ • 到文件头::1 • 到行头:0 • 到行尾:$
Shell命令/10 • Vi编辑器 • 输入模式 • 插入命令:i • 追加命令:a • 新建一行:o • 替换命令:r、s • 复制:yy – p • 建议:远端windows用户用eltraedit通过ftp编辑文件
Shell语言/1 • Shell基础知识 • 命令行语法 • command [arg1][arg2] ...[arg n] • 标准输入/标准输出 • 重定向:〉 • 管道:| • 后台运行:&
Shell语言/2 • 控制结构 • if-then、if-then-else、if...then...elif • for. . . i n • for结构 • while结构 • until结构 • break和c o n t i n u e语句 • case结构
Shell语言/3 • 参数与变量 • 关键字变量:环境变量 • 用户自定义变量 • 位置参数:$0, $1 • 特殊参数:$?, $$
Shell • 运行Shell脚本 • 赋予执行权限,直接运行 • sh sh_script • 自动启动一个服务 • /etc/init.d • /etc/rcX.d目录下建符号连接(S/K前缀) • 是否有命令实现?
提纲 • 如何开发高质量的软件 • UNIX文件系统 • UNIX的SHELL • UNIX开发与调试 • 经验分享 • 讨论
编译 • gcc、g++ • gcc test.c –o test • g++ test.cpp –o test • 编译选项:-O3、-g、-c • 自动编译:make • 编写Makefile
调试 • gdb:面向源代码和目标码 • 可视化的调试工具? • 程序里人工加入debug信息 • /proc中看信息(对于服务程序)
调试(linux) • 怎样用gdb从目标级作debug? • 使用带调试信息的选项编译:gcc -g • 让程序down掉(segment fault)的时候产生core文件:ulimit –c unlimited • gdb ./test core.XXXX • Gdb下常用命令:where、frame X、print
进程和线程/1 • 进程是系统资源管理的最小单位,线程是程序执行的最小单位。线程和进程十分相似,不同的只是线程比进程小,因而调度的开销也比进程小。 • 一个程序里面的所有的线程都在同一个运行空间中执行,而一个程序的子进程则是运行在另外的执行空间中的。所以线程之间的所有资源都是共享的,而平级进程之间的资源不共享,子进程也只继承父进程的资源,但不能共享。 • 同一个进程中的某个线程的故障可以影响其它的线程,因为所有的线程共享同一个虚拟内存空间以及其他资源。例如,某个线程对没有初始化的指针进行写操作,就可能影响其它的线程。而一个出了问题的进程是不会影响其它的进程的,因为它们分别在不同的进程空间进行自己的操作。 • 线程之间共享数据是很方便的,因为不同的线程本来就是共享同样的存储空间。(然而这里就要非常仔细的处理竞争的情况。)而不同进程之间共享数据则需要使用一些IPC机制,例如管道、共享内存、套接字等等 • 创建新的进程需要进行内存的拷贝操作,这就额外的增加了系统负担,而线程则不需要这个拷贝过程。不过由于现在的操作系统的实现是仅仅当内存需要改变的时候才拷贝改动的部分,所以这里的影响相对还是比较小的。 • 线程通常用在某些需要比较好的同步操作的场合。例如,某个问题可以分解为多个几乎对等同步处理的任务的话,则是用线程是很好的选择。进程则适合应用在不需要严格的同步的场合。
进程和线程/2 • 进程编程 • fork • 进程之间的通信方式 • 共享空间:mmap、shmget • 管道 • Socket • IPC • 文件 • 临界资源的竞争-锁 • 文件锁flock • 线程锁:将锁变量定义为共享变量
进程和线程/3 • 线程编程(pthread) • Pthread_create • Phread_destroy • Pthread_detach • Pthread_join • Pthread_attr_XXXX • Pthread_mutex_init • Pthread_mutex_lock • Pthread_mutex_unlock
进程和线程/4 • 线程间通信 • 共享空间:全局变量 • 管道 • Socket • IPC • 文件 • 临界资源的竞争-锁 • 线程锁 • 信号灯+线程锁
进程和线程/5 • Linux下进程/线程模型的测试结果-1(创建与销毁) • 系统支持的最大进程数是14000多个,在系统总的进程数没有达到这个数时,一个进程可以创建的进程个数不受限制 • 系统支持的最大线程数是14000多个,一个进程可以允许300个左右线程同时存活(包括detach和不detach的);但如果线程创建后detach,且会自行退出,一个进程便可以创建多余300个线程,如果线程创建后不detach,即使自行退出,一个进程可以创建的线程数仍为300个 • 进程创建和销毁的开销与CPU主频有关,CPU主频越高,开销越小;与CPU个数关系不大 • 线程创建和销毁的开销与CPU主频、CPU个数、创建后是否detach都有关系,CPU主频越高,开销越小;开销与CPU个数不成反比,CPU个数越多,开销反而越大;线程创建后detach,比不detach的开销小很多 • 线程创建/销毁的开销比进程创建/销毁的开销小很多
进程和线程/6 • Linux下进程/线程模型的测试方案-2(运算型)
进程和线程/7 • Linux下进程/线程模型的测试结果-2(运算型) • 在单CPU的情况下,进程/线程数的增加对运算性能影响不大 • 不是进程/线程数越多越好,当进程/线程数太多的时候,反而影响性能 • 当进程/线程数达到CPU数的时候,更多的进程/线程就不能增加性能了 • 超线程的影响不总是正面的,如进程/线程数等于实际物理CPU数的时候,不开放超线程的性能更高;当进程/线程数多于实际物理CPU数的时候,开放超线程就有优势了
进程和线程/8 • Linux下进程/线程模型的测试方案-3(共享内存通信型 )
进程和线程/9 • Linux下进程模型的测试结果-3(共享内存通信型 ) • 在单CPU情况下,读进程数增多,对于性能增加不大 • 采用进程池的方法时,进程个数与CPU个数(逻辑的)相等比较合适,数量更多并不能提高性能 • 动态创建进程的方法,只适合于队列元素较少,或者每个元素处理复杂,需要占用很多时间的情况;而进程池的方法对于队列元素处理不需占用太多时间,且元素个数又很多的情况,很适合 • 超线程的影响不总是正面的,如在进程池的测试中:进程数等于实际物理CPU数的时候,不开放超线程的性能更高;当进程数多于实际物理CPU数的时候,开放超线程就有优势了 • 超线程对于动态创建进程的情况,比不开放超线程略有优势
进程和线程/10 • Linux下线程模型的测试结果-3(共享内存通信型 ) • 在单CPU情况下,读线程数增多,对于不但不能增加性能,反而会降低性能 • 采用线程池的方法时,线程个数与CPU个数(逻辑的)相等比较合适,数量更多并不能提高性能 • 动态创建线程比动态创建进程性能要好 • 超线程的影响不总是正面的,如在线程池的测试中:线程数等于实际物理CPU数的时候,不开放超线程的性能更高;当线程数多于实际物理CPU数的时候,开放超线程就有优势了 • 当处理复杂元素时,超线程对于动态创建线程的情况,比不开放超线程略有优势;而对于简单元素,则相反。不过这种差别很小
提纲 • 如何开发高质量的软件 • UNIX文件系统 • UNIX的SHELL • UNIX开发与调试 • 经验分享 • 讨论
多用man命令 • man 2 XXX:查看系统调用的联机帮助 • man 2 read • man 3 XXX:查看库函数的联机帮助 • man 3 fread • man 5 XXX:查看配置文件的联机帮助 • man 5 inittab
编码规范 • 严格遵守编码规范 • 做好代码走查 • 例子: • if (a == NULL)最好写成:if (NULL == a) • free A,最好写成: If (NULL != A ) { free (A); A = NULL; }