会员: 密码:  免费注册 | 忘记密码 | 会员登录 网页功能: 加入收藏 设为首页 网站搜索  
游戏开发 > 程序设计 > 入门基础
后台模拟多任务的实现
发表日期:2007-01-17 13:59:30作者: 出处:  

记得以前学过 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';
}

返回顶部】 【打印本页】 【关闭窗口

关于我们 / 给我留言 / 版权举报 / 意见建议 / 网站编程QQ群   
Copyright ©2003- 2024 Lihuasoft.net webmaster(at)lihuasoft.net 加载时间 0.00276