x86汇编利用int 16h中断实现伪多线程输入
x86汇编利用int 16h中断实现伪多线程输入
我们都知道,如果想让一个程序,同时又干这个,又干那个,最好的办法就是多线程。这个在高级语言里面已经用烂了。
但是,DOS是只有单线程的。我如果想让程序在运行的同时,又能接受我键盘的输入,那要怎么办呢?
例如,我有一个DOS彩票开奖软件。屏幕上有十个数字在滚动,当我按下空格键的时候,它会停止跳动,按别的键无效。那么要怎么操作?
首先,接收输入最常用的是int 21h中断里的7号功能调用。但是它是一个中断输入,也就是为了接收这个输入,我的程序就暂停在这儿不动了。但是我彩票开奖数字一直在滚动,那要怎么办啊?不能说我按一下它滚动一下吧。
于是请来了今天的主角,int16h中断。
首先我们看看int 16h中断有哪些功能?
BIOS提供了int 16h中断例程供程序员调用,且功能是从软件层面上实现键盘I/O功能中断调用,功能号为0,1,2,并且必须把功能号放在ah寄存器中。
0号功能调用
mov ah,01h
int 16h
功能:从键盘读入字符送进al寄存器,执行时,等待键盘输入,一旦输入,输入字符的ASCII码放入al中。若al为0,则ah为输入的扩展码。但是,如果键盘缓冲区已有数据,则会读取键盘缓冲区数据,并且将其从缓冲区中删除。
0号功能的工作流程为:
- 检测键盘缓冲区是否有数据;
- 没有则回到1;
- 读取缓冲区第一个字单元中的键盘输入;
- 将读取的扫描码送入ah,ASCII码送入al;
- 将已读取的键盘输入从缓冲区中删除
1号功能调用
mov ah,01h
int 16h
功能:用于查询键盘缓冲区,对键盘扫描但是不等待(也就是不会中断程序),并设置标志寄存器中的ZF。如果有键盘输入(即键盘缓冲区不空),则ZF=0,AL存放的是当前输入的ASCII码,AH存放的是输入字符的扩展码。若无键盘操作,则标志位ZF=1。
2号功能调用
mov ah,02h
int 16h
功能:检查键盘上各特殊功能键的状态。执行后,各种特殊功能键的状态放入AL寄存器中,这个状态字记录在内存0040H:0017H单元中,若对应位为“1”,表示该键状态为“ON”,处于按下状态;若对应位为“0”,表示该键状态为“OFF”,处于断开状态。
mov ah,02h
int 16h ;从键盘输入
and al,04h ;判断是否按下Ctrl
jnz Ctrl_on
Ctrl_on:
......
了解了以上功能,我们来看如何实现伪多线程输入。
mainLoop:
mov ah,01h ;检测是否有输入
int 16h
jz offKey ;jz是当zf=1时跳转,也就是无输入
;如果有输入,没有跳转
mov ah,00h ;那么键盘缓冲区已不为空
int 16h
cmp al,32 ;和空格的ASCII码比较
je spaceProc
...
spaceProc:
...
offKey:
...
这个框架简单易懂,先从mainLoop中判断是否有输入:
- 如果没有任何输入,则直接执行offKey中的代码内容;
- 如果有输入,会调用0号功能对键盘缓冲区进行检索。因为我们已知它有输入(键盘缓冲区不为空),所以不会中断程序。
- 如果键盘输入为空格,就跳转到spaceProc,否则再加别的代码。
- 当然,我们可以利用这个做很多事情,不只是判断空格。
这样,利用int 16h中断中0号功能和1号功能的联动,我们实现了在只支持单线程的DOS中,实现了伪多线程的输入判断。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!