您当前的位置:首页 > 精选知识 > 正文

win10卸载软件,win10怎么卸载(30天自制操作系统day12)

关于【win10卸载软件】,win10怎么卸载,今天乾乾小编给您分享一下,如果对您有所帮助别忘了关注本站哦。

内容导航:1、win10卸载软件,win10怎么卸载,如何卸载软件程序2、30天自制操作系统day12: 初步认识定时器Timer并优化「1」

1、win10卸载软件,win10怎么卸载,如何卸载软件程序

微软发布了win10新系统,很多人纷纷安装使用。但还是有些人不熟悉win10的操作,例如,明明知道win10系统里有很多程序不用的却不知道怎么卸载软件。这就郁闷了,为此,接下来,我们就来看看win10如何卸载软件程序。

操作方法

首先,打开“开始菜单”,点击“设置”。

点击“应用”。

点击“应用和功能”。

选择不需要的程序,点击“卸载”。

弹出对话框,点击“卸载”

操作方法2

还有其它方法,使用“第三方软件”,如360软件管家。

点击进入360软件管家的官网,点击立即下载。

下载完成后,进入360软件管家,点击“卸载”,在列表里选中想要卸载的程序,点击卸载。

稍等片刻后,卸载完成。

2、30天自制操作系统day12: 初步认识定时器Timer并优化「1」

昨天day11我们完成了多窗口显示部分,那么既然有多个窗口了,每个窗口其实都可以有个任务的。

如果每个窗口内都运行各自的任务的话,就是多窗口多任务一起运行的系统了,这与我们目前手头使用的操作系统就差别不大了。

那么多任务的并行计算如何实现呢?

多任务的实现,依赖于定时器。

任务很多,真正去计算任务的计算器却很少。单核心cpu就只有一个计算器。4个核心也就只有4个计算器。任务可以有成百上千个。

所以,需要把每个计算核心的计算时间划片,任务们轮流在计算核心上执行一段时间,也就是说每个任务只在指定的时间片内工作。

属于当前任务的时间片结束,当前任务结束。下一个任务开始,加一个任务的时间片就开始消耗。

那么这个时间片的划分,就需要定期器了。

因为cpu如果自己去计算时间,要注意不被其他指令干扰,因为时间是在一刻不停地走着,但是cpu不能专心计时,它要并行执行很多事情。

也就是说:利用cpu来计时,其实原理上来说得通,但是效果不好。计时工作最好单独交给一个专用的硬件设备,这个硬件设备就叫定时器Timer,它可以像鼠标,键盘一样,作为cpu的外围设备,配合cpu的工作。

鼠标跟cpu如何配合?鼠标有动作,就会给cpu发送中断。

那么定时器呢?定时器所设定的时间到了,也会给cpu发送中断。

所以,要想把定时器使用起来,其实还是要写C的中断函数,汇编的中断函数,要在IDT中写入汇编中断函数的首地址。使用定期器这个cpu的外部设备,与使用像鼠标,键盘这样的外部设备是一样的。

今天的内容,我会按照这个顺序去展开:

定时器Timer利用定时器制作超时器实现对多个超时器的管理加速

最终的效果:

win10卸载软件,win10怎么卸载(30天自制操作系统day12)

定时器Timer

什么是定时器?到设定的时间就产生中断的设备,就叫“设定时间的机器”,简称“定时器”。

到多长时间就产生中断呢?这个需要设定的。

怎么设定呢?

如果要设定1秒钟中断100次,每10ms中断一次,我该怎么操作才能把这个10ms设定给定时器呢?

100=1193.18K / 11932

把11932这个值设定给定期器就行了

设定的方法,使用如下init_pit函数:

#define PIT_CTRL0x0043#define PIT_CNT00x0040# pit: Programmer Interval Timer 可编程中断定时器void init_pit(void){ // 给端口0x0043写入数值0x34,设置定时器位可设定状态io_out8(PIT_CTRL, 0x34); // 0x9c2e是11932的十六进制io_out8(PIT_CNT0, 0x9c);// 把0x9c2e高位写入定期器io_out8(PIT_CNT0, 0x2e);// 把0x9c2e低位写入定期器return;}

上面的公式中,100是1秒钟中断的次数,后面的1193.18K是什么呢?

11932又是什么呢?为什么把11932写入到定时器,就可以每10秒钟中断一次了?

其实,定时器内部相当于运行着一个for循环:

for(i=0;i<设定值;i++){ 一个指令周期;//每循环一次,消耗定时器的一个指令周期}发送中断请求;//运行了设定值个指令周期,产生中断

我们设定值=11932,

那么一个指令周期是多少呢?如果知道指令周期了,11932*指令周期=10ms,那么就是每10ms发送一次中断了,达到我们要求了。

定期器的频率是1193.18K,那么定期器的一个指令周期就是1/1193.18K

所以:11932*1/1193.18K = 11932/1192180 约等于0.01秒=10ms.

对,我们的设定值,就是定期器的指令周期次数。所以,设定时间就是定时器周期时间X设定数。

那么,设定数= 设定时间/定期器周期时间=设定时间X定期器频率

设定数= 10msx1193.18K=11931.9 ,设定数必须取整,所以设定数为11932,对应16进制为0x9c2e.

问:设定2ms产生一次中断,设定值应该是多少?

计算:设定数=2msx1193.18K=2386.36,取整后为2386。

再问:这个定期器,能设定的最短多长时间产生中断?

计算:最短时间其实就是设定数为1时,那么时间间隔=定期器周期*设定数=1/1193.18k*1=1/1193.18K 秒。

所以,一个定期器的能力是有限的,它能分辨的最小时间长度是有下限的。

再问:这个定期器,能设定的最长多长时间产生中断?

计算: 1/1193.18K x 65535

能设定的值最大就是65535了。所以一个定时器,其实能力非常有限,它是有上限的。

最后一问:如果我想定一个时间,2年, 这个时间远远超过了定期器的上限了,我该怎么办呢?

让定期器多中断几次就行了。中断一次耗时10ms, 中断2年/10ms次就行了嘛。

所以,从这个角度来说,定时器又是无上限的。

定时器的下限是无法突破的,有什么办法突破呢?大家可以讨论讨论。这个下限很难突破,但是一旦突破,总会带来很多高精尖的科技产物。

所以,不要小看一个专门定时的芯片,这里面大有学问。

好了,回到课堂上。

给定时器设定好值后,如何在我们自己的操作系统中使用呢?

先把中断函数完成

// 因为要超上限的使用定期器,所以我们设计一个结构来来控制定时器// timer control 定时器控制器struct TIMERCTL { // 记录定时器产生中断的次数 // 一次10ms,count次就是10*count 毫秒unsigned int count;};// 声明一个定时器控制器struct TIMERCTL timerctl;void init_pit(void){io_out8(PIT_CTRL, 0x34);io_out8(PIT_CNT0, 0x9c);io_out8(PIT_CNT0, 0x2e); // 在设定定时器为10ms的时候,把次数count设定为0timerctl.count = 0;return;}// 中断记录表中增加新的中断函数asm_inthandler20,这个中断函数是汇编写set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);// 汇编写的中断函数_asm_inthandler20:PUSHES ;栈处理PUSHDSPUSHADMOVEAX,ESPPUSHEAXMOVAX,SSMOVDS,AXMOVES,AXCALL_inthandler20 ;这里调用C写的中断函数POPEAXPOPADPOPDSPOPESIRETD // C写的中断函数void inthandler20(int *esp){io_out8(PIC0_OCW2, 0x60);// 告诉cpu,本次中断已经处理timerctl.count++; // 次数j加1 return;}

然后再把中断函数中操作的count显示出来,

// 操作系统中的无限循环for (;;) { // 将timerctl.count写入ssprintf(s, "%010d", timerctl.count);boxfill8(buf_win, 160, COL8_C6C6C6, 40, 28, 119, 43);// 将s绘制到背景窗口上 putfonts8_asc(buf_win, 160, 40, 28, COL8_000000, s);sheet_refresh(sht_win, 40, 28, 120, 44); ...}

最终效果用诗篇演示如下:

视频加载中...

利用定时器制作超时器

超时器是记录定时器中断次数来计算是否超时的。

所以,超时器需要设定一个次数的阈值,我们称为timeout.

然后当count次数超过timeout后,我们要执行什么动作呢?

当然是显示出来了。

但是能在中断函数中显示么?不能,因为中断函数内不适合运行太耗时的显示程序。

那怎么办? 中断函数里先把已经超时的这个状态存到一个FIFO的数据就结构里。

然后在操作系统的主循环里再从FIFO数据里读状态,进行显示。

这种利用FIFO结构来顺序的保存数据,又读出使用的方式,其实模仿了我们对鼠标,键盘的操作。

上代码:

// 多加3个变量,实现超时器控制器struct TIMERCTL {unsigned int count; // 计数次数unsigned int timeout; // count被timeout超过时,发生超时,将data写入fifostruct FIFO8 *fifo; //定义先入先出FIFO结构体unsigned char data; //定义写入FIFO结构体的数值};void init_pit(void){io_out8(PIT_CTRL, 0x34);io_out8(PIT_CNT0, 0x9c);io_out8(PIT_CNT0, 0x2e);timerctl.count = 0;timerctl.timeout = 0; // 把超时次数在开始的时候设置为0return;}// 我们还需要对这些值进行设定void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data){int eflags;eflags = io_load_eflags();io_cli();timerctl.timeout = timeout; // 设定timeouttimerctl.fifo = fifo; // 不像鼠标,硬件自己会产生值,然后放入fifo // 超时器这里我们就自己设定一个值,然后放入fifotimerctl.data = data; // 设定当中断发生时,要设置到fifo的值,io_store_eflags(eflags);return;}// 中断函数,// 在运行中断函数前,我们已经对timeout设定了我们需要的超时的值,比如timeout=1000void inthandler20(int *esp){io_out8(PIC0_OCW2, 0x60);timerctl.count++;if (timerctl.timeout > 0) { timerctl.timeout--; // 就给timeout减1if (timerctl.timeout == 0) { // 如果timeout=0,说明count已经达到timeout设定的值了fifo8_put(timerctl.fifo, timerctl.data);// 在fifo结构体中放入data,这个data在操作系统的主函数中会被取出}}return;}

把定时器控制器改造成超时器控制器后,就可以在主函数中使用了:

// 操作系统的主函数Main 中,使用超时器void HariMain(void){ ... // 像处理鼠标数据一样,用先入先出的结构体来处理超时器的数据 // 因为我们也要先入先出的处理超时器 struct FIFO8 timerfifo;char s[40], keybuf[32], mousebuf[128], timerbuf[8]; ... // 把数组首地址给先入先出结构体timefifo // 也就是把数组交给先入先出结构来来管理 fifo8_init(&timerfifo, 8, timerbuf); //设置timeout=1000, 要存入的数据设置为1settimer(1000, &timerfifo, 1); .. for(;;) { ... // 当 定时器的 fifo中有数据时,说明超时了 if (fifo8_status(&timerfifo) != 0) {i = fifo8_get(&timerfifo); io_sti(); // 显示10秒钟已到putfonts8_asc(buf_back, binfo->scrnx, 0, 64, COL8_FFFFFF, "10[sec]");sheet_refresh(sht_back, 0, 64, 56, 80);} ... }

这里,我们成功把定时器改造成了超时器。

利用定时器中断的此时来判断是否超时。

在多线程时,我们就可以判断一个线程运行时间到,让线程先暂停了

不过,现在只有一个超时器,我们多线程时,是有多个线程时,

最好是每个线程都有其对应的超时器,能不能实现?

能。

模仿多层的实现,设计控制器,来实现多个超时器

实现对多个超时器的管理

把timeout, fifo,data等数据抽取出来作为超时器,定义为单独的结构体TIMER,

然后在定时器控制器中,保存500个定时器

// 超时器结构体TIMERstruct TIMER {unsigned int timeout, flags; //flags 表示超时器有没有被线程使用struct FIFO8 *fifo;unsigned char data;};// 在TIMERCTL中定义500个超时器#define MAX_TIMER500struct TIMERCTL {unsigned int count;struct TIMER timer[MAX_TIMER];};

改造完基本数据结构后,还需要改造如下函数:

#include "bootpack.h"#define PIT_CTRL0x0043#define PIT_CNT00x0040struct TIMERCTL timerctl;#define TIMER_FLAGS_ALLOC1#define TIMER_FLAGS_USING2//void init_pit(void){int i;io_out8(PIT_CTRL, 0x34);io_out8(PIT_CNT0, 0x9c);io_out8(PIT_CNT0, 0x2e);timerctl.count = 0;for (i = 0; i < MAX_TIMER; i++) {timerctl.timer[i].flags = 0; //设置所有500个超时器都没有被线程使用}return;}// 从超时器控制器中,分配一个超时器出去// 类似分配一个层出去struct TIMER *timer_alloc(void){int i;for (i = 0; i < MAX_TIMER; i++) {if (timerctl.timer[i].flags == 0) {timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;// 将分配出去的超时器的flags设置为1return &timerctl.timer[i];}}return 0; // 如果所有超时器被使用完了,就返回0}void timer_free(struct TIMER *timer){timer->flags = 0; // 把当前超时器设置为空闲可用return;}void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data){timer->fifo = fifo;// 设置超时器对应的fifotimer->data = data;return;}void timer_settime(struct TIMER *timer, unsigned int timeout){timer->timeout = timeout; // 设置超时器的超时对应的次数timer->flags = TIMER_FLAGS_USING; // 把超时器设定为2,表示可以使用return;}void inthandler20(int *esp){int i;io_out8(PIC0_OCW2, 0x60);timerctl.count++; //遍历所有500个超时器for (i = 0; i < MAX_TIMER; i++) { // 如果超时器的标志时可以使用的,说明已经设置完成,可以开始工作了if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {timerctl.timer[i].timeout--; //超时次数到 if (timerctl.timer[i].timeout == 0) { // 超时器标志设置为1,表示需要重新设定超时值,才能被使用timerctl.timer[i].flags = TIMER_FLAGS_ALLOC; // 把1存入fifo中,等待在main函数for循环中被取出fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);}}}return;}

已经改造好的数据结构,可以在主程序代码中使用他们来完成3个超时器

void HariMain(void){ ... // 准备3个超时器需要的fifo struct FIFO8 timerfifo, timerfifo2, timerfifo3; // 准备3个超时器需要的fifo所控制的数组char s[40], keybuf[32], mousebuf[128], timerbuf[8], timerbuf2[8], timerbuf3[8];// 准备3个超时器结构体 struct TIMER *timer, *timer2, *timer3; ... // 从超时器控制器里分配个位置出来,让timer来用 timer = timer_alloc(); // 把timerfifo给timer用,并把要存入fifo的数据设置为1timer_init(timer, &timerfifo, 1); // 设置超时时间为1000*10ms=10秒timer_settime(timer, 1000); // 设置第二个超时器fifo8_init(&timerfifo2, 8, timerbuf2);timer2 = timer_alloc();timer_init(timer2, &timerfifo2, 1); // 设置超时时间为300*10ms = 3秒timer_settime(timer2, 300); // 设置第3个超时器fifo8_init(&timerfifo3, 8, timerbuf3);timer3 = timer_alloc();timer_init(timer3, &timerfifo3, 1); // 设定超时时间为10ms*50 = 0.5秒timer_settime(timer3, 50); // main函数的for循环 for(;;){ ... // 如果第一个超时器发生超时了 if (fifo8_status(&timerfifo) != 0) {i = fifo8_get(&timerfifo); // 取出超时的数据io_sti(); // 打印出10[sec]字样putfonts8_asc(buf_back, binfo->scrnx, 0, 64, COL8_FFFFFF, "10[sec]");sheet_refresh(sht_back, 0, 64, 56, 80);} else if (fifo8_status(&timerfifo2) != 0) {// 如果第二个超时器发生了i = fifo8_get(&timerfifo2); io_sti(); // 打印出3[sec]字样putfonts8_asc(buf_back, binfo->scrnx, 0, 80, COL8_FFFFFF, "3[sec]");sheet_refresh(sht_back, 0, 80, 48, 96);} else if (fifo8_status(&timerfifo3) != 0) {// 如果第3个超时器,0.5秒的那个超时器发生超时了i = fifo8_get(&timerfifo3); // 下面的设置,我们完成一个光标的绘制io_sti();if (i != 0) { //当 fifo中的这个数据是1时,绘制白色光标timer_init(timer3, &timerfifo3, 0); // 下次该擦除光标了,设置要发送的数据为0 // 绘制白色光标boxfill8(buf_back, binfo->scrnx, COL8_FFFFFF, 8, 96, 15, 111);} else {// 当fifo中的取出的数据是0时,擦除光标timer_init(timer3, &timerfifo3, 1); // 下次该绘制白色光标了,设置要发送的数据为1 // 绘制背景色,相当于擦除白色光标boxfill8(buf_back, binfo->scrnx, COL8_008484, 8, 96, 15, 111);}timer_settime(timer3, 50);sheet_refresh(sht_back, 8, 96, 16, 112);} ... }

我们其实可以设置500个超时器,不过这里我们只设定了3个超时器。

一个用于对10秒的超时检测,一个用于对3秒的超时检测,另外一个用于0.5秒的超时检测

0.5秒的超时器是用于光标显示的。

其实,这就相当于3个计时的线程在并行运行了。

只从运行结果来看,看起来是并能运算。

终于看到了实现并行运算的希望了。

但是这里还有个问题:在中断函数中,我们却遍历3个超时器。分别对这3个超时器的timeout进行减法操作

能不能把减法操作去掉?

对于500个超时器的话,相当于可以减少500次减法。

加速

其实不要把timeout定义为次数,要把timeout定义为到定时器的count加到多少时,就超时。

超时器初始化的时候,timeout = 当前定时器的count + 1000

然后,在中断函数中,检查定时器的count>=timeout了,我们就认为10秒钟超时了

这样,就不需要减法了。

更改后的代码:

void timer_settime(struct TIMER *timer, unsigned int timeout){ // 将timeout的值设置为:count再加timeout次所有达到的值timer->timeout = timeout + timerctl.count;timer->flags = TIMER_FLAGS_USING;return;}void inthandler20(int *esp){int i;io_out8(PIC0_OCW2, 0x60);timerctl.count++;for (i = 0; i < MAX_TIMER; i++) {if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {if (timerctl.timer[i].timeout <= timerctl.count) {// 当count终于加到timeout时,发生超时timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);}}}return;}

要注意的是,我们需要定期的给定时器的count清零。当count清零的时候,每个超时器也要减去count的值。

这样做,只是减少了一些减法。

在中断函数中有个含有500次遍历的for循环,总结觉得是可以优化的,优化后是一定会有较大的提升的。

怎么优化呢?核心思想是什么?

每次只检查最小timeout有没有被count超过就行了.如果最小的timeout都没有被count超过,那就没有必要检查其他超时器了。

这样就成功的把 500次降低为1次了,很顶吧

思想有了,按照这个思想来改下代码:

void inthandler20(int *esp){int i;io_out8(PIC0_OCW2, 0x60);timerctl.count++;if (timerctl.next > timerctl.count) {return; // next就是timeout最小的超时器,就是下一个要达到的超时器 // 如果next的值count就没有达到,那么中断函数返回,什么也不做} // 当count超过最小的超时器的timeout值next了timerctl.next = 0xffffffff; // 再遍历检查500个超时器,for (i = 0; i < MAX_TIMER; i++) {if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {if (timerctl.timer[i].timeout <= timerctl.count) {timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;// 记录超时状态 fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);} else {// 对于没有超时的超时器,把超时值记录到next中, // 因为如果next大于timeout,那么next设置为timeout // next总被设置为比它小的值 // 所以遍历到最后,next就是所有超时器中,最小的那个timeout了if (timerctl.next > timerctl.timer[i].timeout) {timerctl.next = timerctl.timer[i].timeout;}}}}return;}

改完了。

在最小的超时器没有被count达到的时候,中断函数不做任何操作。

效果不错。

但是,当最下的超时器达到了之后,我们又要遍历500个超时器了。

所以,这里仍然可以继续改。

新设定一个参数using,来遍历flag处于可以记录的状态的超时器。

新设定一个列表timer来存放 按照timeout排序后的using个超时器.

struct TIMERCTL {unsigned int count, next, using; //增加usingstruct TIMER *timers[MAX_TIMER]; //增加times,存放排序后的using个超时器struct TIMER timers0[MAX_TIMER];};//在设定超时器的时候,就按照timeout排序,按照timeout的值,放在timer中的顺序的位置void timer_settime(struct TIMER *timer, unsigned int timeout){int e, i, j;timer->timeout = timeout + timerctl.count;timer->flags = TIMER_FLAGS_USING;e = io_load_eflags();io_cli();//找到当前超时器应该放的位置ifor (i = 0; i < timerctl.using; i++) {if (timerctl.timers[i]->timeout >= timer->timeout) {break;}}//把大于等于i的超时器往后移一位,for (j = timerctl.using; j > i; j--) {timerctl.timers[j] = timerctl.timers[j - 1];}timerctl.using++;//把timer放在timectl.timers的第i个位置timerctl.timers[i] = timer;timerctl.next = timerctl.timers[0]->timeout;io_store_eflags(e);return;}// 在中断函数中,就只用检查timectl.timer[0]的timeout又没被达到就行了void inthandler20(int *esp){int i, j;io_out8(PIC0_OCW2, 0x60);timerctl.count++;if (timerctl.next > timerctl.count) {return;}for (i = 0; i < timerctl.using; i++) {// 在超时器控制器中添加一个变量using,来记录当前正在工作的超时器的个数 // 这样,我们就就处理using=3个超时器就可以了if (timerctl.timers[i]->timeout > timerctl.count) {break;}//如果当前超时器达到了timerctl.timers[i]->flags = TIMER_FLAGS_ALLOC; //发出超时信号fifo8_put(timerctl.timers[i]->fifo, timerctl.timers[i]->data);}// using-1timerctl.using -= i; // 把与第i个超时器从所有的正在工作的超时器列表中去掉for (j = 0; j < timerctl.using; j++) {timerctl.timers[j] = timerctl.timers[i + j];} // 如果using大于0,那么将下一次要达到的值nex设置为timers中第0个if (timerctl.using > 0) {timerctl.next = timerctl.timers[0]->timeout;} else {timerctl.next = 0xffffffff;}return;}

到这里,我们的优化终于到一段落了,终于把500次遍历去掉了。

有几个定时器在用,我们就多少次遍历。

大大节省了不必要的计算。

今天的定时器教程就到这里。

我们显示利用中断完成了最基本的定时器,每10ms发生一次中断。

然后我们又用这个定时器,完成了3个超时器,并行运行,分别在0.5秒,3秒,10秒的时候发生在屏幕上绘制内容。

这看起来就很并行了。

明天,day13, 是不是可以进行多线程并行了?

还不行,对定时器的使用还需要更多的优化, 我们会在在day13把对定时器的优化结束掉。

然后在day14 把屏幕的分辨率提高一下。多任务的时候,需要多个窗口了,屏幕太小操作起来不方便。

day15,我们实现多任务并行处理。

本文关键词:win10卸载软件。这就是关于《win10卸载软件,win10怎么卸载(30天自制操作系统day12)》的所有内容,希望对您能有所帮助!


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: 错误1068依赖服务或组无法启动(Windows10防火墙错误1068依赖服务或组无法启动,怎么办)

下一篇: 低芥酸菜籽油骗局(低芥酸菜籽油和一般菜籽油的区别)



推荐阅读