导航:首页 > 源码编译 > api相似度实现算法

api相似度实现算法

发布时间:2022-08-08 13:46:51

Ⅰ 任务管理的其他

4.4.1任务状态及转换时序
在上面的章节中,描述了任务的三种基本状态,一般在实现时会基于这三种转态添加新的状态。图4-4描述了实际实现的任务状态转换图。在给定的时刻,任务的状态一定处在这六种状态之一,下面的论述只是对本系统实现的描述,不同的内核对这些部分的实现有很大差异,但基本原理不变。
图4-4在描述任务状态迁移的同时,也描述了任务的生存周期,任务的生命期从新建态时开始直到结束态时结束。在不同的操作系统中,这些状态的实现是有差异的,有的内核还有其他状态。新建状态是指任务被创建的过程,在这个过程中主要工作有:为任务分配TCB和栈空间以及其他资源。当任务创建完成以后,任务就具备运行的能力了,与此同时,任务进入就绪状态,并等待调度器为它分配运行的机会。当任务得到运行的机会,任务开始执行。处于运行态的任务会在任意时刻由运行态进入休眠态、就绪态或结束状态。其中进入休眠态是任务的主动过程,这主要是任务调用了内核提供的休眠函数,任务在休眠状态,如果没有其他任务唤醒它,它将永远休眠下去直到系统关闭,这种方式也可用于任务同步。等待状态主要由两种原因引起,一种是等待某事件的发生,如等待信号量;第二种为任务主动等待多少个tick。最后,任务可以将自己杀死进入结束态。
4.4.2任务控制
任务控制块(TCB)唯一地描述了一个任务的属性。一旦任务建立了,任务控制块中的各个值将被赋值。任务控制块是一个数据结构,当任务的CPU使用权被剥夺时,TCB保存了该任务的状态和其他信息。当任务重新得到CPU使用权时,TCB能确保任务从被中断的点丝毫不差地继续执行。TCB全部驻留在RAM中。TCB在任务初始化的时候被建立。任务控制块数据结构如下所示:
typedef struct task_ctrl_blk{
stk_t *pstack;
stk_t *pstk;
list_t link;
uword_t id;
uword_t prio;
uword_t slice_time;
uword_t exe_time;
word_t delay_time;
uword_t status;
list_t task_link;
}tcb_t;
其中:
·pstack:指向当前任务的栈顶。每个任务有自己的栈,尤为重要的是,每个任务的栈的容量可以是任意的。有些商业内核要求所有任务栈的容量都一样,除非用户写一个复杂的接口函数来改变之。这种限制浪费了RAM,当各任务需要的栈空间不同时,也得按任务中预期栈容量需求最多的分配栈空间。pstack是TCB数据结构中唯一一个能用汇编语言来处置的变量(在任务切换段的代码之中使用)把pstack放在数据结构的最前面,使得从汇编语言中处理这个变量时较为容易;
·pstk:指向任务的栈顶,在任务结束而回收任务栈空间时使用,这主要由内存管理部分的缺陷所引起的;
·link:用于连接任务控制块。内核在运行时,除了任务控制块外,系统中存在很多类型的链表,比如信号量链表。为了对这些链表有一个统一的操作,所以定义了list_t类型来统一这些操作。如果不使用list_t,TCB链表操作需要实现一组链表操作函数,信号量需要另外一组链表操作函数,这样使程序变得冗长;
·id:任务的ID号,用于唯一标识一个任务。每个任务都有一个唯一的ID号,需要在任务创建的时候指定ID,如果指定的ID号已经存在,则此任务不能被创建;
·prio:任务的优先级,此值范围为0~63,值越小代表优先级越高。内核将尽力保证高优先级的任务优先运行,并且允许任务可以是相同的优先级;
·slice_time:表示任务应该运行的时间片数。虽然内核保证高优先级的任务优先得到运行的机会,但对于相同优先级的任务来说,时间片方式是比较好的调度策略;
·exe_time:保存了任务已经运行的时间片个数。这个变量在每次系统时钟中断产生时被累加1,如果exe_time的值达到slice_time,则说明该任务已经运行了给定时间片的时间,这时,内核将把运行机会让给其他的,且优先级等于此任务的其他任务。如果此优先级上没有其他任务,且此任务没有自己放弃运行机会,此任务将继续运行;
·delay_time:用于记录任务等待的时间片数,每个系统时钟中断产生时,此值自减1,如果delay_time的值为0,说明该任务的等待时间已经超时。内核将此任务从等待队列中删除,并移动就绪队列中,这样该任务就会被调度器在适当的时候调度;
·status:指示了任务的运行状态,目前,此值表示的含义有就绪,休眠,等待和阻塞,在任务状态转换图4-4中的运行态未能表示出来,这是因为在实现时,就绪态同时也表示了运行态;
·task_link:用于将系统中所有的任务连接成循环双链表。
4.4.3 ByCore中的各种队列
在图4-4中描述的每个状态都对应一个或一组队列。如处于就绪状态中的就绪队列,处于等待态中的等待队列等等。
4.4.3.1 就绪队列
就绪队列中的任务已经得到除CPU以外的所有资源。调度器也将在它们中按照优先级和时间片结合的策略选择一个就绪任务获得CPU。在实现中,任务被分成64(0~63)种优先级,且不同的任务又会有相同优先级。内核将相同优先级的任务组成一个双链表。为了在调度过程中能快速的检索出最高优先级的任务队列,将整个就绪队列用一个全局数组list_t ptask[MAX_PRIO](其中MAX_PRIO=64)来作为不同优先级就绪队列的队头,如ptask为优先级是i的就绪队列的队头。整个就绪队列如图4-5所示。
4.4.3.2 等待和休眠队列
当任务处于等待或休眠态时,内核必须将该任务的TCB从就绪队列中删除,然后插入到等待或者休眠队列。在当前的实现中,内核只分别维持一个等待队列和休眠队列,这两个队列不像就绪队列按照优先级的高低被分组,换句话说,等待队列和休眠队列将所有的任务TCB连成一个双链表。
pdelay和psleep分别为等待队列和休眠队列的对头指针。这两个队列的组织虽然一样,但是它们各自队列中的任务被激活的时机却不同,pdelay所指队列中的任务会被内核的tick激活,而处在psleep队列中的任务只能由其他的任务将其唤醒。利用这两种队列配和信号量等任务同步、通信机制可以实现较为复杂、灵活的任务控制机制。
当任务处在等待态时,任务还可能处在另外的队列中,这个队列就是为等待某个信号量而组织成的队列。这个队列将在信号量实现的内容中论述。
4.4.4调度器实现
在整个任务管理中,任务调度无疑是系统的核心,任务调度通常由内核中的调度器实现。调度器的实现与任务运行状态迁移,任务队列有密切的联系,可以说任务运行状态迁移和任务队列决定了调度器的实现。调度器的主要作用是在就绪队列中选择优先级最高的任务运行,如果优先级最高的任务不止一个,则选择队头的任务运行。虽然整个调度器的功能可以用上面的几句话概括,但调度器的实现远远没有那么简单,主要困难来源下面的原因:
1.确定调度器运行的时机;
2.中断处理程序完了后,是执行当前任务,还是马上调度;
3.调度器的性能;
4.调度中伴随着任务上下文的切换,尤其对处理器架构有关的上下文,应该设计良好的接口以便移植。
以上这些基本问题都是应该考虑的,随着内核功能的扩充和完善,调度器可能会在原先没涉及到的地方被调用,虽然在这些新地方不要求能正确调度,但至少不能引起系统崩溃。对于实时系统来说,中断处理程序执行完毕后,应该马上执行调度,这是因为中断常常伴随着有新的任务处于就绪队列中,在这些任务中可能会有高优先级的任务就绪,所以在实时内核中要求必须支持在中断后马上进行任务调度。不管是在实时系统,还是在其他系统中,调度器性能显得非常重要,常常要求调度器的时间复杂度至少应该为线性,当然常数是最好的。对于不同的处理器架构,其提供的寄存器,状态寄存器都有很大的区别,调度器应该留出良好的接口给不同的处理器,以便以后方便移植。
在实现调度器时,基本上考虑了上面的几个基本问题。根据上两节论述的任务状态迁移、内核队列等方面的内容,在byCore中实现了一个叫scheler( )的调度程序。在scheler( )中调用几个与硬件相关的函数,这几个函数主要用于实现任务硬件上下文的切换,这部分代码用汇编完成,并且与处理器有关。在现代操作系统中,会有很少一部分使用汇编语言实现,这是因为各种处理器架构的寄存器都没有被映射到可见的位置,也即象C这样的高级语言不能直接对其操作,然而,在任务切换时,硬件上下文会保存到任务堆栈中,这种操作使得高级语言无能为力。
该调度程序的算法非常简单,首先,在允许调度的情况下,如果有高优先级任务就绪,则进行任务切换。任务切换会发生在两种处理器模式下,一种是处理器处于正常的运行态,另一种发生在中断态中。因此,内核使用两组函数分别处理这两种情况。在两种处理器状态下都有“启动新任务”和“新旧任务切换”函数接口实现最后的任务切换工作,这两组函数与处理器有关,并由汇编实现。在后面的内核移植一节将详细论述这些函数接口的实现。
启动新任务的主要功能是将任务的初始上下文复制给处理器的各个寄存器,这包括通用寄存器、堆栈指针寄存器、状态寄存器和指令指针寄存器等。这些初始值在新任务创建时被初始化。启动新任务发生的时机有两种情况,第一种情况是内核初始化完毕后,启动第一个任务;第二种情况为任务主动结束后,当前任务指针被置位NULL时。
任务切换发生在两个任务之间,一个是被换切换出去的任务,另一个是将要执行的任务。任务切换函数也由汇编代码实现。它所要完成的工作主要有两个,第一是将旧任务(被换切换出去的任务)的上下文保存到自己的栈中,第二是新任务(将要执行的任务)将保存在栈中的上下文复制到处理器的相关寄存器中。任务切换的发生时机有:
· 当前任务执行时间到;
· 当前任务被高优先级任务抢占;
· 当前任务休眠,或等待某事件发生。
由于任务切换与处理器关系紧密,本章只介绍与处理器无关部分的实现,与处理器有关的部分将在内核移植一章中详细论述。
4.4.5 内核时钟实现
在内核时钟一节中,论述了内核时钟的作用以及功能。但在当前实现中,根据实际的情况对内核时钟的功能做了裁减,内核时钟功能主要由systick( )函数实现。
4.4.6 任务管理API实现
任何内核都应该提供一组丰富的API函数供用户使用。像UNIX、Linux、Windows这些大型操作系统提供了大量的API。当然这些API的数量、种类,用法等都会随着系统的不同而不同。但在任务管理方面下面几个API是必不可少的:任务创建、撤销、休眠、等待和唤醒等操作。下面将描述各个API的实现算法。
4.4.6.1 任务创建
当用户调用任务创建函数时,内核应该完成哪些工作呢?这和内核的实现方式,复杂程度密切相关。当前任务管理实现中,提供两个任务创建函数osInitTask( )和osCreateTask( )。这两个函数的原型如下所示:
void osInitTask(void (*pTask)(), uword_t TaskID, uword_t Prio, uword_t Time, uword_t StkSize);
void osCreateTask(void (*pTask)(), tcb_t *pTcb, uword_t TaskID, uword_t Prio, uword_t Time, stk_t *pStk, uword_t StkSize);
这两个函数的主要区别为任务需要的TCB和栈空间是否为动态创建。osInitTask( )函数只需要传递任务起始地址((*pTask)()),任务ID(TaskID),优先级(Prio),运行时间片(Time)和栈大小(StkSize),任务的栈和TCB空间都为动态创建,栈和TCB空间处于系统的堆区。osCreateTask( )函数除了以上的参数外还格外需要*ptcb和*pstk两个参数,这两个参数分别指向任务的TCB起始地址和栈起始地址,这个函数的空间需要在编译时制定,栈和TCB空间属于内核区。虽然它们需要的参数不同,但它们的实现算法是相同的。
在描述算法之前需要对任务栈做简单的论述,栈的作用是保证任务正常运行,它保存了任务中各个函数的调用轨迹和返回地址。对于处理器来说都提供一个独立的寄存器或者其他空间保存着栈顶的位置,各种处理器架构对栈顶和栈底的定义也不相同,这主要有两种,一是栈顶的地址值大于栈底,其二相反。第一种伴随着栈往下增长,第二种栈往上增长。为了便于移植内核,内核应该处理这两种情况。除了这两种情况,栈还分为满栈和空栈两种,所以内核必须考虑这几种栈方式。因此在实现中提供一组宏来应对这些情况,如下所示:
#define UP 1
#define DOWN 0
#define FULL 1
#define EMPTY 0
#define STACK DOWN
#define STACK_STYLE FULL
UP和DOWN定义了栈的增长方向,FULL和EMPTY说明了是满栈还是空栈。最后用STACK和STACK_STYLE联合说明真正的栈工作方式。
论述完了任务创建方面需要注意的一些问题,下面论述任务创建的算法。任务创建过程主要包含初始化TCB和栈区,如果调用osCreateTask( )函数,在初始化前还需要向内核申请TCB和栈空间。图4-9为osInitTask( )函数创建新任务的流程图。
4.4.6.2 任务撤销
每个任务都有一个生命周期,包括任务创建、运行与撤销。任务撤销也可称为在多任务系统中,任务也可以被任何用户杀死,也可以有特殊用户杀死。比如,杀死任务。任务撤销的方式有很多种实现方式。一般情况下,任务可以被内核杀死。在Linux下有些任务可以被任何用户杀死,有些则只能由root用户杀死。在单用户系统中,用户任务能被内核杀死,也可以被其他用户任务杀死,但后种情况不多见。根据实际的情况,当前对任务撤销的实现为只有任务自己主动杀死自己。
在当前实现中,任务撤销的函数为osKill( ),如果当前任务完成了自己的使命,可以调用该函数。osKill( )会释放掉该任务的相关资源,如TCB和栈空间等。osKill( )只释放掉内核分配的资源,如果任务的运行过程中申请了其他资源,应该在调用osKill( )前释放掉这些资源。任务在创建时有两个创建函数osInitTask( )和osCreateTask( ),osKill( )只能释放osInitTask( )的资源,而osCreateTask( )的资源会被保留下来。这是因为osCreateTask( )所使用的空间属于内核空间,而不属于系统动态内存管理的堆区,这部分区域没有相关的数据结构管理,一旦释放系统就会崩溃。根据上面的描述可以设计出osKill( )的算法,该算法如图4-10所示。
4.4.6.3 任务休眠与唤醒
当任务需要等待某些资源的时候,可以将自己设为休眠状态,把运行的机会让给其他任务,当所等待的资源或者事件发生时,任务再被唤醒继续运行。这种方式也是解决任务同步的一种办法,如任务A与任务B合作完成某项任务,且A完成后B才能运行,休眠与唤醒机制可以很容易地解决此问题。内核实现了两个函数分别完成这两项工作,他们是osSleep( )和osWakeUp( ),osSleep( )是任务的主动行为,因此不需要参数,osWakeUp( )需要一个参数TaskID,该参数指定了需唤醒任务的ID号。
当任务调用osSleep( )后,该任务的TCB从就绪队列中删除,并插入到休眠队列(如图4-6所示),然后重新调度。如果任务A需要唤醒正在休眠的任务B,那么A可以调用osWakeUp( )函数,并传入B的ID。osWakeUp( )就会查找休眠队列,如果找到任务B,则将它的状态置为就绪,并从休眠队列删除插入就绪队列。
4.4.6.4 任务等待
任务等待与任务休眠的实现原理都一样。任务在等待一段时间后再获得运行的机会,这个时候它所等待的事件或者资源有可能不可用,这点和任务休眠是有差异的。例如任务A需要与串口I/O通信,由于串口速度相对较慢,任务A大部分时间都需要等待,如果任务A在没有数据传输的时候进入等待状态,将会显着提高CPU利用率。
内核提供了osWait( )函数来实现此功能,该函数接受一个时间参数,该参数说明当前任务等待时间长短,该时间以系统tick为单位。当前任务调用此函数后,任务状态被置为等待态,TCB从就绪队列中删除,并插入到等待队列,最后调度scheler( )。等待队列与休眠队列相同,见图6-7所示。osWait( )函数的流程图与osSleep( )算法相似,这里不再赘述。
每次系统tick发生中断时,内核时钟中断处理程序更新等待队列上任务的等待时间域,也就是任务控制块TCB的delay_time域作减1操作,当此域减少到0时,表示该任务的等待时间已到,这时它将从等待队列中删除,并插入到就绪队列中。这些工作也是内核时钟中断当前唯一需要做的事情。

Ⅱ 求大神啊!!使用api实现 快速排序算法最好用c++

C/C++ 中的快速排序 API 就是 qsort。

#include<iostream>
usingnamespacestd;

intcmp(constvoid*a,constvoid*b)
{
inti1=*((int*)a);
inti2=*((int*)b);
returni1-i2;
}
intmain()
{
intn=16;
intarr[]={3,12,1,999,56,77,32,4,99,12,67,65,43,22,2000,88};
cout<<"排序前:"<<endl;
for(inti=0;i<n;++i)
{
cout<<arr[i]<<"";
}
cout<<endl;

qsort(arr,n,sizeof(arr[0]),cmp);

cout<<"排序后:"<<endl;
for(inti=0;i<n;++i)
{
cout<<arr[i]<<"";
}
cout<<endl;
return0;
}

编译运行:

Ⅲ C#怎么来判断2张图片相似度

很麻烦,而且计算量很大,这个属于人工智能的范畴。

如果这“两张相似图片”可以规定很多前提,比如相同分辨率,黑白,简单几何图形。。。那么可以用基本的算法去算一下“相似度”, 也就是楼上说的,读取两张照片的像素点,然后遍历去对比灰度差值。这些有很多现成的算法,也有很多网站提供这方面的计算(直接调用API即可),但是只能得出数字化的“相似度”。


如果你要的就是两张图片像素点之间的差异,那么就去找算法即可实现。

看一参考这个网站:www.aforgenet.com 这个是国外比较知名的图像处理的网站。


但是,两张图片如果尺寸不一呢? 如果比例不一样呢? 如果有留白呢?彩色的呢?

所以目前最成熟的编程算法也就是识别一下字母和数字(比如谷歌可以识别照片上的门牌号和街道号),人脸识别也只是拿几个标本部位来大致判断相似度(眼睛的大小,鼻梁的高度,脸颊的宽瘦和比例), 以人眼的标准完整的去比较两张图片是否一样是很难的,目前应该还没有这方面成熟的技术。

Ⅳ 编程开发一个网络应用系统——图谱分析系统,用java语言实现,小女无知,还望各位编程高手慷慨出手相助

我做好了 嘿嘿

Ⅳ 请教SAPI

可以的。他有一个相似度的,一般是负数。越靠近0,相似度越大。

Ⅵ 正在在毕设,请问用VC++处理图像相似度的算法

建议你找一本vc++图形图像编程的书,在前面的几章都会讲怎么取图像数据,都有事例代码,其实说起来也很简单,就是通过api把数据部分从图像文件里取出来,然后根据图像的调色板转成颜色数据,我推荐你找周长发的vc++图形图像处理,所有事例都有代码并且可以直接使用,里面的代码虽然执行效率不高,但是结构非常清晰,适合学习使用。

Ⅶ 有没有好的判断图片相似度的库

很麻烦,而且计算量很大,这个属于人工智能的范畴。
如果这逗两张相似图片地可以规定很多前提,比如相同分辨率,黑白,简单几何图形。。。那么可以用基本的算法去算一下逗相似度地, 也就是楼上说的,读取两张照片的像素点,然后遍历去对比灰度差值。这些有很多现成的算法,也有很多网站提供这方面的计算(直接调用API即可),但是只能得出数字化的逗相似度地。


如果你要的就是两张图片像素点之间的差异,那么就去找算法即可实现。
看一参考这个网站: 这个是国外比较知名的图像处理的网站。


但是,两张图片如果尺寸不一呢看 如果比例不一样呢看 如果有留白呢看彩色的呢看
所以目前最成熟的编程算法也就是识别一下字母和数字(比如谷歌可以识别照片上的门牌号和街道号),人脸识别也只是拿几个标本部位来大致判断相似度(眼睛的大小,鼻梁的高度,脸颊的宽瘦和比例), 以人眼的标准完整的去比较两张图片是否一样是很难的,目前应该还没有这方面成熟的技术。

Ⅷ 用Java 8 增加的 Stream API 能实现哪些优雅的算法

Java 8引入了全新的Stream API。这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。

Stream API引入的目的在于弥补Java函数式编程的缺陷。对于很多支持函数式编程的语言,map()、rece()基本上都内置到语言的标准库中了,不过,Java 8的Stream API总体来讲仍然是非常完善和强大,足以用很少的代码完成许多复杂的功能。

创建一个Stream有很多方法,最简单的方法是把一个Collection变成Stream。我们来看最基本的几个操作:
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Stream<Integer> stream = numbers.stream();
stream.filter((x) -> {
return x % 2 == 0;
}).map((x) -> {
return x * x;
}).forEach(System.out::println);
}

集合类新增的stream()方法用于把一个集合变成Stream,然后,通过filter()、map()等实现Stream的变换。Stream还有一个forEach()来完成每个元素的迭代。

为什么不在集合类实现这些操作,而是定义了全新的Stream API?Oracle官方给出了几个重要原因:

一是集合类持有的所有元素都是存储在内存中的,非常巨大的集合类会占用大量的内存,而Stream的元素却是在访问的时候才被计算出来,这种“延迟计算”的特性有点类似Clojure的lazy-seq,占用内存很少。

二是集合类的迭代逻辑是调用者负责,通常是for循环,而Stream的迭代是隐含在对Stream的各种操作中,例如map()。

要理解“延迟计算”,不妨创建一个无穷大小的Stream。

如果要表示自然数集合,显然用集合类是不可能实现的,因为自然数有无穷多个。但是Stream可以做到。

自然数集合的规则非常简单,每个元素都是前一个元素的值+1,因此,自然数发生器用代码实现如下:
class NaturalSupplier implements Supplier<Long> {

long value = 0;

public Long get() {
this.value = this.value + 1;
return this.value;
}
}

反复调用get(),将得到一个无穷数列,利用这个Supplier,可以创建一个无穷的Stream:
public static void main(String[] args) {
Stream<Long> natural = Stream.generate(new NaturalSupplier());
natural.map((x) -> {
return x * x;
}).limit(10).forEach(System.out::println);
}

对这个Stream做任何map()、filter()等操作都是完全可以的,这说明Stream API对Stream进行转换并生成一个新的Stream并非实时计算,而是做了延迟计算。

当然,对这个无穷的Stream不能直接调用forEach(),这样会无限打印下去。但是我们可以利用limit()变换,把这个无穷Stream变换为有限的Stream。

利用Stream API,可以设计更加简单的数据接口。例如,生成斐波那契数列,完全可以用一个无穷流表示(受限Java的long型大小,可以改为BigInteger):
class FibonacciSupplier implements Supplier<Long> {

long a = 0;
long b = 1;

@Override
public Long get() {
long x = a + b;
a = b;
b = x;
return a;
}
}

public class FibonacciStream {

public static void main(String[] args) {
Stream<Long> fibonacci = Stream.generate(new FibonacciSupplier());
fibonacci.limit(10).forEach(System.out::println);
}
}

如果想取得数列的前10项,用limit(10),如果想取得数列的第20~30项,用:
List<Long> list = fibonacci.skip(20).limit(10).collect(Collectors.toList());

最后通过collect()方法把Stream变为List。该List存储的所有元素就已经是计算出的确定的元素了。

用Stream表示Fibonacci数列,其接口比任何其他接口定义都要来得简单灵活并且高效。

阅读全文

与api相似度实现算法相关的资料

热点内容
微信解压游戏怎么下载 浏览:961
忍三服务器不同如何登上账号 浏览:821
php求积 浏览:294
封面命令 浏览:879
手机复制文件夹到另一个文件夹 浏览:992
手游为什么不能统一下服务器 浏览:246
iphone上pdf 浏览:884
window定时python脚本 浏览:64
怎么运行cmd命令行 浏览:366
php中类的继承 浏览:228
openvpnlinux安装配置 浏览:463
PHP7从入门到精通 浏览:27
单片机生日 浏览:500
linux当前进程号 浏览:728
老死pdf 浏览:25
云服务器关机网址不见了 浏览:69
余冠英pdf 浏览:756
开发一个app上市需要什么步骤 浏览:28
phpsleep方法 浏览:430
时间同步服务器ip地址6 浏览:926