记得以前学过 Win9x/NT的利用时间片轮转实现了多任务,而其中又用时钟中断作为任务调度的方法。每次发生时钟中断,多任务系统就自动保存当前任务的各种状态,标志到状态表。更新任务时间表,判断所有任务的状态:激活/挂起/死锁了。然后利用一定的算法找出最迫切需要运行的进程,接着读取并恢复它的状态表,利用一个jmp或者iret指令完成调度切换。
在DOS下是单任务系统,而编程常常需要多任务的功能,诸如条色板流动,MIDI播放,WAVE混音。等等需要和主程序同时运行的进程。于是就有人开始设计使DOS进程支持多任务的程序,然而写成前面所说的那种未免太大动干戈了,许多任务并不会占用许多时间,如MIDI播放,TSR检测,色彩流动等每个循环只是占用及少的时间,于是我们的代码可以简化了,我们模拟的多任务系统可以简化到按一定频率激活进程,并且要求进程自动放弃时间片,否则就overfollow,如此实现是很简单的:
首先设置中断服务程序MyInt8()并保存老的中断,然后编程系统时钟芯片把时钟滴答从18.2次/秒改 成200次/秒(见SetTimerRate()),完成初始化(见lt_install_timer())。每次发生中断是服务程序 MyInt8()就扫描任务表,统计出各个任务需要运行多少次,然后再分别运行。注意一定要先统计再运行我以前忽略这点,因为有些进程会自己将自己remove,如果不先统计而是边运行边更新时间表的话由于remove后speed变为0而会死循环造成 overfollow。中断服务程序结束时要判断是否到运行老的Int8的时间,否则就用写0x20到端口0x20发送中断结束信号。如此反复运行达到了我们期望的目的。
可以看出我的代码接口是和Allegro一样的,因为大家一看就知道具体用法了。但我并没有copy Allegro的方法,因为我开始写后台服务程序时还不知道Allegro是什么,下面是代码:LTIMER.H LTIMER.CPP TIMEDEMO.CPP,这里有它们打包了的源程序。
第一部分: // 后台时钟系统控制程序, // 提供16个不同速率的进程同时运行,中心控制程序分时定义为1/200 // 秒一个时间片,程序在 Borland C++3.1编译并通过, // // Copyright (c) 1997,2000 Newbird, written by Skywind // 请访问无名鸟工作室 http://newbird.126.com //
#ifndef LTIMER_H #define LTIMER_H
#define TRUE 1 #define FALSE 0
#ifndef MIN #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #define MID(x,y,z) MAX((x), MIN((y), (z))) #endif
void lt_install_timer(); // 初始化时钟系统 void lt_remove_timer(); // 结束系统 // 如果你不还原,系统会自动在程序结束是还原 long lt_clock(char swit); // 取时钟,参数swit为0,1代表取1.198181Hz 和200Hz的时钟 char lt_install_int_ex(void (*proc)(),long speed); // 设置并激活进程, // speed代表1198181Hz的系统时钟为标准的停顿时间 char lt_install_int(void (*proc)(),long speed); // 设置并激活进程 // speed代表千分之几秒 void lt_remove_int(void (*proc)()); // 结束系统
#endif
第二部分: // Timer Control // support 16 processes running in different // rate and in the same time // // Copyright (c) 1997,2000 Newbird, written by Skywind // for more information please see http://newbird.126.com //
#include <stdio.h> #include <stdlib.h> #include <dos.h> #include <conio.h> #include "ltimer.h" #define MAX_TIMERS 16
void lt_install_timer(); void lt_remove_timer(); long lt_clock(char swit); // 0: 1.19MHz 1:200Hz the same char lt_install_int_ex(void (*proc)(),long speed); char lt_install_int(void (*proc)(),long speed); void lt_remove_int(void (*proc)());
static long tinstall=0,autoexit=0,Timer_Delay=65536L; static long lt_clock0=0, lt_clock1=0; short lt_Intr=0x08;
// 进程定义结构 static struct { void ((*proc)()); // 进程指针 long speed; // 进程的速度 long counter; // 计数器 } my_int_queue[MAX_TIMERS+1];
// 换算定义 #define TIMERS_PER_SECOND 1193181L #define SECS_TO_TIMER(x) ((long)(x) * TIMERS_PER_SECOND) #define MSEC_TO_TIMER(x) ((long)(x) * (TIMERS_PER_SECOND / 1000)) #define BPS_TO_TIMER(x) (TIMERS_PER_SECOND / (long)(x)) #define BPM_TO_TIMER(x) ((60 * TIMERS_PER_SECOND) / (long)(x)) #define LOVE_TIME_SPEED BPS_TO_TIMER(200)
static void interrupt MyInt8(...); static void interrupt far (*OldInt8)(...); static void SetTimerRate(unsigned long v); static int FindProc(void (*proc)()); static void UpdateRate();
// 再进程表中寻找一个与proc匹配的函数指针 // 如果没有找到则返回一个没有分配的进程 static int FindProc(void (*proc)()) { int i; for (i=0;i<MAX_TIMERS;i++) if (proc==my_int_queue[i].proc) return i; i=0; while (my_int_queue[i].proc&&i<MAX_TIMERS) i++; // Find a new space my_int_queue[i].speed=my_int_queue[i].counter=0; return i; }
// 删除进程 void lt_remove_int(void (*proc)()) { int i=FindProc(proc); my_int_queue[i].proc=NULL; my_int_queue[i].speed=my_int_queue[i].counter=0; }
// 启动进程 char lt_install_int_ex(void (*proc)(), long speed) { int i=FindProc(proc); my_int_queue[i].proc=proc; my_int_queue[i].counter-=my_int_queue[i].speed; my_int_queue[i].counter+=speed; my_int_queue[i].speed=speed; if (i<MAX_TIMERS) return 1; return 0; }
// 更新时钟服务程序频率 static void UpdateRate() { int i; long new_speed=65536L; for (i=0;i<MAX_TIMERS;i++) if (my_int_queue[i].proc&&my_int_queue[i].speed<new_speed) new_speed=my_int_queue[i].speed; if (new_speed!=Timer_Delay) { Timer_Delay=new_speed; if (Timer_Delay>65536L) Timer_Delay=65536L; SetTimerRate(Timer_Delay); } }
// 以千分之x秒为运行频率启动进程 char lt_install_int(void (*proc)(),long speed) { return lt_install_int_ex(proc,MSEC_TO_TIMER(speed)); }
// 返回系统记录的时钟 long lt_clock(char swit) { if (!tinstall) lt_install_timer(); if (swit==0) return lt_clock0; return lt_clock1; }
// 中断服务程序 static void interrupt MyInt8(...) { register short i; static long old_delay=65536L, old_counter=65536L; static short callback[MAX_TIMERS];
lt_clock0+=Timer_Delay; lt_clock1++; // 更新时钟
// 统计每个进程需要运行几次 for (i=0;i<MAX_TIMERS;i++) { callback[i]=0; if ((my_int_queue[i].proc) && (my_int_queue[i].speed>0)) { my_int_queue[i].counter-=Timer_Delay; while (my_int_queue[i].counter<=0) { my_int_queue[i].counter+=my_int_queue[i].speed; callback[i]++; } } }
// 实际运行进程。 for (i=0;i<MAX_TIMERS;i++) { while(callback[i]>0) { if (my_int_queue[i].proc) (*my_int_queue[i].proc)(); callback[i]--; } }
// 处理老时钟 old_counter-=Timer_Delay; if (old_counter<=0) { old_counter+=old_delay; if (lt_Intr==0x08) _chain_intr(OldInt8); }
_enable(); if (lt_Intr==0x08) outportb(0x20,0x20); }
// 更新服务程序频率 static void SetTimerRate(unsigned long v) { if (v>65536||v==0) v=65536; _disable(); outportb(0x43, 0x34); outportb(0x40, v & 0xff); outportb(0x40, v >> 8); _enable(); Timer_Delay=v; }
// 初始化 void lt_install_timer() { int i; if (tinstall) return; OldInt8=_dos_getvect(lt_Intr); _disable(); _dos_setvect(lt_Intr,MyInt8); _enable(); tinstall=1; SetTimerRate(LOVE_TIME_SPEED); for (i=0;i<MAX_TIMERS;i++) my_int_queue[i].proc=NULL; if (!autoexit) { atexit(lt_remove_timer); autoexit=1; } }
// 返回服务程序停顿 long lt_report_delay() { return Timer_Delay; }
// 移除中断服务程序并结束 void lt_remove_timer() { if (!tinstall) return; tinstall=0; _disable(); _dos_setvect(lt_Intr,OldInt8); _enable(); SetTimerRate(0); }
这下面就是一个利用整套系统的示例: // 后台时钟系统控制程序, // 提供16个不同速率的进程同时运行,中心控制程序分时定义为1/200 // 秒一个时间片,程序在 Borland C++ 10.0编译并通过。 // // Copyright (c) 1997,2000 Newbird, written by Skywind // 请访问无名鸟工作室 http://newbird.126.com //
#include "LTIMER.CPP"
#include <stdio.h> #include <conio.h>
char *VideoBuf=(char *)0xb8000000L; void process1(); void process2(); void process3();
long delay_timer[3]={ 50, 200, 1000 };
void main() { lt_install_timer(); printf("Timer system installed\n"); lt_install_int(process1,delay_timer[0]); lt_install_int(process2,delay_timer[1]); lt_install_int(process3,delay_timer[2]); printf("Setup 3 process at the different speed\n"); printf("press any key to stop process1\n"); getch(); lt_remove_int(process1); printf("press any key to stop process2\n"); getch(); lt_remove_int(process2); printf("press any key to stop all process and quit\n"); getch(); lt_remove_timer(); // this action will stop all the process first printf("Good bye, Timer Demo written by Skywind\n"); printf("For more information please see NewBird Group http://newbird.126.com\n"); }
void process1() { static int counter='A'; VideoBuf[80]=counter; if (++counter>'Z') counter='A'; } void process2() { static int counter='a'; VideoBuf[82]=counter; if (++counter>'z') counter='a'; } void process3() { static int counter='0'; VideoBuf[84]=counter; if (++counter>'9') counter='0'; }
|