参考《Unix/Linux编程实践教程》
插个情趣事件:贝尔实验室的Dennise Ritchie和Ken Thompson为了玩一个叫《星级旅行》的游戏而编写了Unix系统。你信不信,反成我信了,
视频游戏和操作系统有许多共同点?我咋感觉不出来呢,太浅了吧。
在本文介绍一个简单的视频游戏,通过这个游戏来介绍更多的Unix系统服务、一些 基本原则和操作系统设计技术。
先发问?
1.视频游戏做什么?
关于游戏做什么,这要看你做什么游戏,关键在是什么游戏,什么游戏有神马应用,你就做这些东西,满足这些应用,乱了吗,那就对了.........................
比如咱们本文提到的《星级旅行》游戏,你的程序要做出行星、流星、飞船和其它物体的影像,并使它们移动。每个你程序创建的东西都有自己的属性:自己的移动速度、方向、动力和其它属性。物体之间相互联系,作用。流星可能撞上飞船或其它星。
同时游戏要与用户互动,响应用户输入:游戏玩家通过按钮、鼠标和轨迹球在任何时刻都有可能生成输入,程序必须在短时间内做出响应。这些输入时间会影响前面提到的创建的物体的属性,例如增加飞船的移动速度、方向等。
2.视频游戏如何做?
一个视频游戏综合了一些基本的概念和原则。
(1)空间
游戏必须在计算机屏幕的特点位置画影像。
程序如何控制视频显示?
(2)时间
影像在屏幕上移动,以一个特定的时间间隔改变位置。
程序如何获知时间并且在特定的时间触发事情发生呢?
(3)中断
程序在屏幕上平滑的移动物体,用户可以在任意时刻产生输入。
程序是如何响应这些中断的?
(4)并发——同时做几件事
游戏在保证几个影像移动的同时还要响应中断。
程序如何实现同时做这么多事而不被弄得晕头转向呢?
3.操作系统面临的类似问题
操作系统同样要面临上面4个类似的问题。
内核将程序载入内存空间并维护每个程序在内存中所处的位置。
在内核的调度下,程序以时间片间隔的方式运行,同时,内核在特定的时间运行特定的任务。
内核必须在很短的时间内响应用户和外设在任何时刻的输入。
同时,做几件事需要一些技巧。内核是如何保证数据的有序和规整的?
4.屏幕管理、时间、信号、共享资源
本章将学习屏幕管理、时间、信号和如何安全地同时做几件事。
为了学习这4个基本的主题,将编写一个基于字符终端的动画游戏。
一 屏幕编程:curses库
curses库十一组函数,程序员可以利用它们来设置光标的位置和终端屏幕上显示的字符样式。
大部分控制终端屏幕的程序使用curses库
1.1 介绍curses
curses将终端屏幕看做是由字符单元组成的网络,每一个单元由(行、列)坐标对标示。
坐标系的原点在左上角,行坐标自上而下递增,列坐标自左向右递增。
curses的函数可以将光标移动到屏幕上任何行、列单元,添加字符到屏幕或删除从屏幕上,设置字符的属性(颜色、亮度)等,
建立和控制窗口以及其他文本区域。
基本的curses函数
initscr() 初始化curses库和tty
endwin() 关闭curses并重置tty
refresh() 使屏幕按照你的意图显示
move(r,c) 移动光标到屏幕坐标的(r,c)位置
addstr(s) 在当前位置画字符串s
addch(c) 在当前位置画字符c
clear() 清屏
standout() 启动standout模式 (一般使屏幕反色)
standend() 关闭standout模式
上图是第一个屏幕控制实例显示的结构为hello1.c;
hello1.c代码如下:
#include <stdio.h>
#include <curses.h>
main()
{
initscr(); /*turn on curses*/
clear(); /*clear screen*/
move(10,20); /*row10,col20*/
addstr("Hello World"); /*add a string*/
move(LINES-1,0); /*move to LL*/
refresh();
getch(); /*wait for user input*/
endwin(); /*turn off curses*/
}
实例2的运行结果:
hello2.c代码如下:
#include <stdio.h>
#include <curses.h>
main()
{
int i;
initscr(); /*turn on curses*/
clear(); /*clear screen*/
for(i=0;i<LINES;i++)
{
move(i,i+i); /*row10,col20*/
if(i%2==1)
standout();
addstr("Hello World"); /*add a string*/
if(i%2==1)
standend();
//move(LINES 1,0); /*move to LL*/
}
refresh();
getch(); /*wait for user input*/
endwin(); /*turn off curses*/
}
2.2 curses内部:虚拟和实际屏幕
refresh做了什么?
注释掉该行,重新编译,运行程序。结果是什么都没有出现在屏幕上。
curses设计成为能在不阻塞通信线路的情况下更新文本屏幕。
curses通过虚拟屏幕来最小化数据流量。
真是屏幕是眼前的一个字符数组。curses保留了屏幕的两个内部版本。
一个内部屏幕是真实屏幕的复制。另一个是工作屏幕,其实记录了对屏幕的改动。
每个函数比如:move和addstr只在工作屏幕上进行修改。工作屏幕就像磁盘缓存,curses中的大部分函数都只对它进行修改。
refresh函数比较工作屏幕和实际屏幕的差异,然后refresh通过终端驱动送出那些能使真实屏幕与工作屏幕一致的字符和控制码。
例如:如果真实屏幕左上角是Smith、james,然后用addstr把Smith、jane放在相同位置,调用refresh函数也许只是用n和空格替换了james中的m和s。
这种只传输改变的内容而不是影像本身的技术被用在视频流中。
接:下篇《时钟编程》