在 DOS 下实现多线程
在 DOS 下实现多线程
程序在 Turbo C 3.0 下调试通过,采用了最简单的时间片轮转法,实现了多线程的系统,程序尽量采用了最简洁的技术来实现多任务的系统,主要使用到了C标准库中的setjmp和longjmp两个函数,程序绝大部分都是采用C/C++语言书写,但是仍然不可避免的采用了三句内嵌汇编,来进行线程堆栈的切换。由于DOS下的系统调用,都是不可重入的.如果在多个线程中同时调用了DOS的系统调用,就会出现死机等问题。一般可以使用信号量来解决DOS重入问题。整个系统,是使用时钟中断处理程序,来完成任务的调度。
stdefine.h
- /* 标准头文件 */
- #ifndef _STDEFINE_H_
- #define _STDEFINE_H_
- /* 常量定义 */
- #define TRUE 1
- #define FALSE 0
- /* 标准的类型定义 */
- //typedef int BOOL;
- typedef unsigned char BYTE;
- typedef unsigned short WORD;
- typedef unsigned long DWORD;
- typedef long int LONG;
- /* 定义常用的宏 */
- #define LOWBYTE(value) ( (BYTE) ((value) & 0x00FF) )
- #define HIBYTE(value) ( (BYTE) ((value) >> 8) )
- #define LOWWORD(value) ( (WORD) ((value) & 0xFFFF) )
- #define HIWORD(value) ( (WORD) ((value) >> 16) )
- #define MAKEWORD(hi, low) ( (WORD) (((hi)<<8)|(low)) )
- #endif
thread.h
- #ifndef _THREAD_H_
- #define _THREAD_H_
- /* 包含头文件 */
- #include "stdefine.h"
- /* 类型声明 */
- typedef int (*THREADPROC)(void *argv);
- /* 函数声明 */
- int InitMultiThread(unsigned short cycle); /* cycle 主线程的时间片 */
- void CloseMultiThread();
- /* proc 线程入口函数,argv 参数,cycle 线程时间片,返回值:线程ID */
- int CreateThread(THREADPROC proc, void *argv, WORD cycle);
- void DestroyThread(int id);
- void RunThread(int id);
- void StopThread(int id);
- void PauseThread(int t);
- void KeepMainThread(int d); //只运行主线程
- #endif
thread.cpp
- /* 包含头文件 */
- #include <mem.h>
- #include <string.h>
- #include <stdlib.h>
- #include <setjmp.h>
- #include <dos.h>
- #include "stdefine.h"
- #include "thread.h"
- /* 常量定义 */
- #define MAX_THREAD_NUM 5 //16 定义最大的线程数
- #define THREAD_STACK_SIZE 256 //512 定义每个线程申请的内存
- #define THREAD_DEAD 0
- #define THREAD_READY 1
- #define THREAD_RUNNING 2
- #define THREAD_STOPPED 3
- #define _INT_1CH 0x1c
- /* 类型定义 */
- typedef struct
- {
- THREADPROC proc;
- void *argv;
- WORD status;
- int timer; //当前剩余时间
- WORD cycle; //分配的时间片大小
- jmp_buf jmpbuf;
- BYTE stack[THREAD_STACK_SIZE];
- } THREADITEM, PTHREADITEM;
- /* 内部全局变量定义 */
- static void interrupt (*old_int_1ch)(...);
- static THREADITEM thread_list[MAX_THREAD_NUM] = {0};
- static int cur_thread = 0;
- static int main_thread_keep=0; //主线程标志
- extern int graph_sigle; //外部信号量,解决程序不能重入问题,如图形库函数不能重入
- //通常=1
- /* 内部函数声明 */
- static void interrupt MULTI_THREAD_MAN(...);
- static void changetimer(WORD t);
- /* 函数实现 */
- int InitMultiThread(unsigned short cycle) //初始化多线程调度程序
- {
- memset(thread_list, 0, sizeof(THREADITEM) * MAX_THREAD_NUM);
- cur_thread = 0;
- /* main thread cycle */
- thread_list[cur_thread].status = THREAD_RUNNING;
- thread_list[cur_thread].timer = cycle;
- thread_list[cur_thread].cycle = cycle;
- old_int_1ch = getvect(_INT_1CH);
- setvect(_INT_1CH, MULTI_THREAD_MAN);
- return TRUE;
- }
- void CloseMultiThread() //关闭线程序调度
- {
- // changetimer(0);
- disable();
- setvect(_INT_1CH, old_int_1ch);
- enable();
- }
- void KeepMainThread(int d) //选择是否只运行主线程
- {
- if(d==0)
- {
- main_thread_keep=0; //多线程
- disable();
- setvect(_INT_1CH, MULTI_THREAD_MAN); //调度程序重新作用
- enable();
- }
- else
- {
- main_thread_keep=1; //==1时,只运行主线程(单线程)
- }
- }
- int CreateThread(THREADPROC proc, void *argv, WORD cycle) //创建新线程
- {
- int i;
- for (i=0; i<MAX_THREAD_NUM; i++)
- {
- if (thread_list[i].status == THREAD_DEAD)
- {
- thread_list[i].proc = proc;
- thread_list[i].argv = argv;
- thread_list[i].status = THREAD_READY;
- thread_list[i].timer = cycle;
- thread_list[i].cycle = cycle;
- return i;
- }
- }
- return NULL;
- }
- void DestroyThread(int id)
- {
- memset(&thread_list[id], 0, sizeof(THREADITEM));
- }
- void RunThread(int id) //重新开启原先被暂停的线程
- {
- disable();
- thread_list[id].status = THREAD_RUNNING;
- enable();
- }
- void StopThread(int id) //用于暂时关闭副线程
- {
- while(1)
- {
- if(graph_sigle==1) //信号为1时才关闭线程
- {
- disable();
- thread_list[id].status = THREAD_STOPPED;
- enable();
- break;
- }
- }
- }
- /* 内部函数实现 */
- static void changetimer(WORD t) //修改单位时间
- {
- outportb(0x43, 0x3c);
- outportb(0x40, LOWBYTE(t));
- outportb(0x40, HIBYTE(t));
- }
- /* 线程调度函数,是整个系统的关键 */
- static void interrupt MULTI_THREAD_MAN(...)
- {
- static int i;
- static int temp;
- /* 关中断 */
- disable();
- if(cur_thread==0 && main_thread_keep==1)
- {
- setvect(_INT_1CH, old_int_1ch); //当运行到主线程时间片且main_thread_keep==1时,关闭线程调度程序
- enable();
- return;
- }
- //多线程调度
- if (--thread_list[cur_thread].timer > 0)
- { /* 当前线程的时间片未用完,不进行线程调度 */
- enable(); /* 开中断 */
- return;
- }
- /* 当前线程的时间片用完,进行线程调度 */
- thread_list[cur_thread].timer = thread_list[cur_thread].cycle; /* 重新分配时间片 */
- if (!setjmp(thread_list[cur_thread].jmpbuf)) /* 保存当前线程的运行环境 */
- { /* 开始线程调度 */
- for (i=0; i<MAX_THREAD_NUM; i++)
- { /* 查找下一个可调度的线程 */
- cur_thread++;
- cur_thread %= MAX_THREAD_NUM;
- if (thread_list[cur_thread].status == THREAD_READY)
- {
- /* 为新线程分配堆栈 */
- temp = (WORD)(thread_list[cur_thread].stack);
- temp += THREAD_STACK_SIZE;
- asm mov sp, temp;
- asm mov ax, ds;
- asm mov ss, ax;
- /* 调用线程函数 */
- thread_list[cur_thread].status = THREAD_RUNNING;
- outp(0x20, 0x20); /* 清除中断屏蔽 */
- enable(); /* 开中断 */
- thread_list[cur_thread].proc(thread_list[cur_thread].argv);
- /* 线程运行结束 */
- disable(); /* 关中断 */
- thread_list[cur_thread].status = THREAD_DEAD;
- longjmp(thread_list[0].jmpbuf, 1); /* 返回主线程 */
- break;
- }
- else if (thread_list[cur_thread].status == THREAD_RUNNING)
- { /* 调度线程 */
- longjmp(thread_list[cur_thread].jmpbuf, 1);
- break;
- }
- }
- }
- outp(0x20, 0x20); /* 清除中断屏蔽 */
- enable(); /* 开中断 */
- }
main.cpp
- /* 包含头文件 */
- #include <stdio.h>
- #include <stdlib.h>
- #include <dos.h>
- #include <conio.h>
- #include "thread.h"
- int graph_sigle=1; //如果多线程中同时有DOS系统调用,用信号量隔开
- /* 以下是测试程序 */
- int fun(void *n)
- {
- while (1)
- {
- sound(1000);
- delay(200);
- nosound();
- delay(200);
- }
- }
- int fun2(void *s)
- {
- printf("%s", s);
- }
- /* 演示了三个线程:主线程、fun 和 fun2 */
- main()
- {
- int id1;
- int id2;
- WORD i = 0;
- InitMultiThread(1);
- id1 = CreateThread(fun, NULL, 1);
- id2 = CreateThread(fun2, (void*)"hello world !/r/n", 1);
- for (i=0; i< 3; i++)delay(1000);
- while (!kbhit())
- {
- printf("rockcarry %u/r/n", i++);
- }
- getch();
- DestroyThread(id2);
- DestroyThread(id1);
- CloseMultiThread();
- nosound();
- }