资源调用

2024-08-01

资源调用(精选12篇)

资源调用 篇1

0 引 言

在个人PC终端、嵌入式系统,尤其是服务器上,基于硬件实现的各种计算资源应用越来越广泛,典型的如高速的密码运算模块、高速的数据压缩等处理模块。这些基于硬件实现的各种运算处理模块极大地加速了上层应用的数据处理能力,尤其是在服务器端,能够缓解由于大量的并发服务连接所带来的运算压力。在并发的环境下,如何让各应用高效公平地使用底层的硬件资源是我们关注的焦点,因此高效的硬件资源调度方法就成为了关键,而针对多阶段调用硬件资源的调度尤其是一个较难处理的问题。

所谓多阶段调用,是指应用对硬件资源的一次使用需要分为多个阶段,而各个阶段必须顺序地不被打断地完成,典型的例子就是对硬件实现的hash算法的调用;应用需要把待处理的数据分块多阶段的送入运算模块处理,在每个阶段,应用都需要和底层硬件进行交互,在此期间,运算模块无法处理其它应用的运算请求。整个调用过程如图1所示。

1 方法描述

针对多阶段调用类型的硬件资源,一般的调度方法有两类。

一类是把调度做在内核层,由硬件驱动来完成资源的调度,通过内核锁的机制来控制应用对资源的竞争[1]。在应用调用硬件的第一阶段就锁住硬件,在应用调用的最后一个阶段结束时解锁,这样其它应用就可以继续争抢锁来使用硬件资源。这个方法看似不错,但是容易出现死锁的情况,比如有一个应用在调用硬件的多个阶段中,在其中的某一个阶段意外终止了,比如程序出错而崩溃,或者被人为的中止,比如管理员中止了相关进程;而此时对硬件的调用还没有到最后一个阶段,也就是说此时的内核锁还没有解开。这样之后的其它应用都将无法获得这个内核锁而出现死等的情况。尽管也有人提出超时等待后自动获得锁,以及增加调用计数等方法,但都无法从根本解决并发竞争的问题。

另一类方法是把调度做在上层,比如做在上层的动态库里[2],这样的话,锁机制实现在应用层,即使有应用崩溃,那么这个锁也可以做到随之消失,而不影响后来应用的调用,也能满足同进程里各线程间的竞争问题。但是这类方法的问题也很多。比如动态库都是每进程空间私有的,也就是说在动态库里实现的锁机制不能很好的控制进程间的竞争,而且效率比内核锁低,处理起来比较麻烦。另外由于相互不熟悉的人,可能对各自的应用、对同样的硬件开发各自不同的动态库,这样由于双方使用的不是同一个库,这样就无法使用锁的机制来做同步。归根结底还是做控制的层次太高的原因。

通过对上面两类方法的分析可以发现,它们均有不能处理的情况,而这些情况在实际应用中是不可避免会出现的。因此,本文提出一种新的基于内核模式的调度方法,来完美地解决这一问题。

本文提出的方法依然是要基于内核模式,在驱动层来做调度,因为只有这样,做到底层,才能实现完全的控制,所有对硬件的调用请求最终都归口到这里。通过前面的分析可以发现,这个调度问题的难点在于,如果程序意外退出,则没有一种有效的机制来解锁硬件,而本文的方法利用操作系统自身的进程维护机制,再加上对象标记跟踪的方法解决了这个问题。

本文描述方法的核心在于以下两点:一是可以找到一种方法来标识当前正在使用硬件的对象;二是在对象意外消亡时,可以找到有效的方法来补救性地完成该对象对硬件资源的占用释放。本文方法的一般性描述如下:

应用对象在第一阶段调用硬件时候获得锁,同时内核驱动对该对象进行标定。

应用对象继续后续的数据处理工作。

应用对象在最后一个阶段调用硬件结束时,释放锁,同时内核驱动解除对该对象的标定。

在硬件设备句柄被关闭时,内核驱动检查发起这个关闭请求的应用对象是否被标定过,如果是,则解除标定并释放内核锁,否则直接进行后续的事务操作。

下面分别以最为常见的Linux操作系统和Windows操作系统为例来具体描述本文方法的细节,并给出依赖于操作系统的具体实现。

2 Linux操作系统下的算法实现

在Linux操作系统下,应用通过驱动来调用硬件时,都是先要打开设备获得设备句柄之后,才能进一步通过设备句柄来和硬件进行交互,在全部工作完成之后,应用会通过close()调用关闭设备句柄,这样就断开了和设备的连接;即使应用忘记了关闭设备句柄,或者说因为意外终止而无法完成设备句柄的关闭动作,操作系统也会在进程结束时进行相应的善后处理,关闭进程打开的所有句柄。也就是说驱动程序的open和release函数是始终会被成对调用的。同时我们也注意到,在驱动程序的open、release、read、write、ioctl等函数接口中,始终都会带有一个struct file * 类型的指针,它就对应于上层应用打开的设备句柄,而struct file结构体里有一个字段void* private_data,也就是说是一个私有域字段,在初始化时被置成NULL[3,4],可以为硬件驱动自由使用,这样驱动就可以使用这个字段来记录需要的信息,比如本句柄对应的上层应用是否正在占用相关的硬件资源。

算法1

(1) 应用打开设备,在驱动中置file-> private_data为free;

(2) 应用在第一阶段调用硬件时候,在内核驱动里争抢锁;

(3) 获得锁之后,在驱动中file-> private_data=busy; 应用进行后续的调用和数据处理;

(4) 应用在最后一阶段调用硬件结束的时候,在驱动中释放锁,并且file-> private_data= free;

(5) 设备句柄关闭时,驱动检查file-> private_data,如果是busy,则首先解锁,并进行驱动内部的资源善后处理,否则直接进行资源善后处理。

通过上面的算法描述可以看出,如果应用正常使用硬件结束,则内核锁会在第(4)步里解锁;如果应用异常退出,则操作系统会代替应用关闭设备句柄,这样在第(5)步,设备驱动就可以安全的解锁硬件资源,之后其它应用依然可以正常的使用。

3 Windows操作系统下的算法实现

在Windows操作系统上,虽然其内核实现机制和Linux下有较大差别,但是也可以使用类似的方法来实现本文描述的方法机制,下面描述一种具体的实现方法。

在Windows操作系统上,程序异常退出时,系统内核也会为该进程进行相关善后处理工作,包括内存的释放,句柄关闭等[5],同样在关闭句柄的时候,设备驱动会得到通知,来释放相应的资源和进行善后。这样在同进程内使用同一设备句柄的前提下(一般来说都是这种情况,在动态库层内部使用同一设备句柄,向应用层屏蔽底层实现细节),本文提出的调度方法可实现如下。

算法2

(1) 应用打开设备,获得句柄;

(2) 应用在第一阶段调用硬件时候,在内核驱动里争抢锁;

(3) 获得锁之后,在驱动中userid=CurrentProcessId; 应用进行后续的调用和数据处理;

(4) 应用在最后一阶段调用硬件结束的时候,在驱动中userid置0并释放锁;

(5) 设备句柄关闭的时候,驱动检查 userid,如果是CurrentProcessId,则userid置0,释放锁,并进行驱动内部的资源善后处理,否则直接进行资源善后处理。

4 试验测试

本文在Linux Red hat 5.5,内核版本2.6.18下,以及Windows XP SP2下面,对一款PCIE硬件hash加速卡进行了调度算法试验。应用对加速卡的调用分为多个阶段,一个Hash_init初始化阶段, 多个Hash_update数据处理阶段,一个Hash_final取数据结果阶段,应用场景符合本文描述的多阶段调用模式。试验首先验证了在正常的硬件使用流程下,调度算法的有效性,这是一个基本测试;然后通过人为加入程序错误等方式来模拟应用异常中止,包括程序在某个Hash_update之后立即退出,在程序中加入除0错误、非法地址访问错误、堆栈溢出等来导致程序异常退出; 以及用户主动终止进程等方式;通过在内核设备驱动中加入调试打印信息来观察调度算法的行为,以验证算法有效性。通过试验验证也表明,本文描述的方法,在上述两类操作系统下的具体实现,均能高效和正确地处理各种调度情况,达到了预期的设计目标。

5 结 语

本文提出一种针对多阶段调用的硬件资源调度方法。通过对硬件使用对象的跟踪标识、以及对象意外消亡后的补救处理技术,正确高效地解决了对多阶段调用的硬件资源的竞争使用问题,尤其是对上层调用者意外退出运行的情况给出了有效的处理方法,保证了后续调用者能继续正常使用硬件资源,整个调度逻辑也能继续正常运转。本文还给出了Linux和Windows这两类不同的操作系统环境下的具体实现细节,并分别进行了试验验证,通过试验也表明,本文提出的调度方法的两个具体实例化算法,能够高效和正确地处理各种调度情况,证明了算法的有效性。

参考文献

[1]Walter Oney.Programming the Microsoft Windows Dirver Model,Sec-ond Edition[M].Redmond,Washington:Microsoft Press,2002.

[2]Jeffrey Richter.Windows核心编程[M].王建华,译.北京:机械工业出版社,2000.

[3]Jonathan Corbet,Alessandro Rubini,Greg Kroah-Hartman.Linux De-vice Drivers[M].O'Reilly Media,2005.

[4]宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2008.

[5]Mark E.Russinovich,David A.Solomon.Microsoft Windows Internals[M].4th ed.Redmond,Washington:Microsoft Press,2004.

资源调用 篇2

病历是医院的财产,医院保管所有患者病历信息(包括门急诊和住院信息),以保护患者、医务工作者和医院的权利和利益。同时,医院要维护病历信息的安全,有计划、随时地为医、教、研提供所需病案资料,提供专题病例资料,规范病人病历的管理,以防止病历丢失、被涂改、被篡改或被未经许可的人使用。2.范围

2.1以下人员可以查阅客户的病历:

2.1.1因执行工作职责而需要查阅病历的医务人员,如患者医疗小组成员、护士、会诊医生、营养师、康复医生等;

2.1.2经医务部同意的因工作关系而需查阅病历的保险公司、上级卫生行政管理部门和国家执法部门等单位的工作人员。

3.定义 4.职责 5.标准

5.1提供再度住院病人的病案借阅。配合临床和防疫部门做好肿瘤、传染病、疑难病的随访工作,对疑难病例、死亡病例讨论,由本院医师借阅并于3日内归还。

5.2在院内借阅病历时,必须由病案室工作人员登记病历去向,实习生和进修生不能从病案室借走病历。

5.3医生科研分析病史只能在病案室内进行分析,一律不得外借住院病历。5.4病历的复印:

5.4.1 根据卫生部《医疗机构病历管理规定》的要求:受理复制病历申请时,申请人必须提供有关证明材料:

5.4.1.1 申请人为患者本人的,必须出示身份证(或有效身份证明)。

5.4.1.2 申请人为患者代理人的,应当提供患者及其代理人的身份证明、申请人与患者代理关系的法定证明材料(委托书)共三项。

5.4.1.3 申请人为死亡患者近亲属的,应当提供患者死亡证明及其近亲属的有效身份证明、申请人是死亡患者近亲属的法定证明材料(户口本或派出所证明)共三项。

5.4.1.4 申请人为死亡患者近亲属代理人的,应当提供患者死亡证明、死亡患者近亲属及其代理人的有效身份证明、死亡患者与近亲属关系的法定证明材料(户口本或派出所证明)、申请人与死亡患者近亲属代理关系的法定证明材料(委托书)共五项。

5.4.1.5 申请人为保险机构的,应当提供保险合同复印件、承办人员有效身份证明、患者本人或其代理人同意的法定证明材料(委托书)共三项;患者死亡的,应当提供保险合同复印件、承办人员有效身份证明、死者近亲属或其代理人同意的法定证明材料共四项。合同或者法律另有规定的除外。

5.4.1.6 公安、司法机关因办理案件需要查阅、复印或者复制病案资料的,必须出示采集证据的法定证明(介绍信)及执行公务人员的有效身份证明(执行公务证)。所有病案资料复印申请人需持如上证明材料向医务部提出申请,经医务部审批同意后方可复印。

5.4.2 根据《医疗事故处理条例》的规定,病人有权复印下列病历资料: 5.4.2.1 门诊病人、住院病人的入院记录;

5.4.2.2 体温单、医嘱单、护理记录、手术及麻醉记录单、化验单(检验报告)、医学影像检查资料、病理资料;

5.4.2.3 特殊检查同意书、手术同意书;

5.4.2.4 国务院卫生行政部门规定的其他病历资料。5.4.3 下列资料不允许病人复印:

5.4.3.1 住院病人的病程录、上级医师查房记录; 5.4.3.2 会诊意见; 5.4.3.3 疑难病例讨论记录; 5.4.3.4 死亡病例讨论记录等。

5.4.4 根据《医疗事故处理条例》的规定,复印病案资料时申请人应当在场,并在复印的病案资料上加盖证明印记。医院病案的复印只在工作日内进行受理并执行,其他法定节假日,若无紧急情况均不受理;若遇紧急情况,则需要由院领导及相关委员会商议通过,方可执行;

5.4.5 登记要求:工作人员须详细记录复印时间、申请人的姓名、病案号、住址、科别、电话、复印缘由等,申请人必须核对登记内容,核对无误后在登记本签字.5.4.6 病案室应妥善保管《病历复印登记本》。6.流程

7.表单

7.1《病历复印登记本》 7.2<《病案借阅管理登记本》

8.相关文件

快速调用系统功能和目录 篇3

1 Shell命令一键调用

由于这些专门的文件夹目录都有一个快捷路径,所以用户只需要使用系统中的Shell命令,就可以快速地一键跳转到想到的地方。比如我们想要进入到系统的“快速启动”目录,只需要在开始按钮上点击鼠标右键,选择菜单里面的“运行”命令(图1)。在弹出的运行对话框里面输入“shell:Quick Launch”后回车,即可快速打开Windows系统的启动目录(图2)。当然用户除了在运行框里面运行操作以外,还可以在资源管理器的路径栏、命令提示符窗口,甚至浏览器的地址栏中直接执行并打开这些系统里面的特殊文件夹目录。

除了特殊的文件夹目录以外,Windows系统里面还有很多系统功能,其实利用Shell命令也可以快速地打开。不过这个时候利用的不是快捷路径命令,而是系统中的GUID信息。比如我们想要打开Windows 10系统的防火墙功能,只需要在输入框里面输入“shell:::{4026492F-2F69-46B8-B9BF-5654FC07E423}”后回车,就可以快速地打开“Windows防火墙”配置管理功能。如果需要打开Windows Defender,那么执行“shell:::{D8559EB9-20C0-410E-BEDA-7ED416AECC2A}”命令即可。

当然了,GUID信息太过复杂,不容易记忆,其实我们可以将上面的命令保存到批处理文件中,放在桌面,需要的时候双击运行,就可以一键打开特殊目录了。

2 如何查找相关信息

无论是快捷路径还是GUID信息,在每一个Windows版本里面都有所不同,那么用户如何查询这些信息呢?首先打开系统的注册表编辑器,接着展开到HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions\,这样在下面就可以看到很多的GUID信息。点击每一个GUID信息后,就可以在右侧窗口里面看到一个Name项目,而它对应的信息内容就是相应的快捷路径(图3)。

调用存储过程的通用方法 篇4

在VB.NET中存储过程分为有返回值的和无返回值的, 不论哪种存储过程, 它的调用方法都可以概括为下面的几步:

(1) 声明一个Sql Connection实例。

(2) 声明一个Sql Command实例, 并且设置其Connection属性为刚声明的Sql Connection实例, 设置Command Name为存储过程名, Command Type为存储过程。

(3) 向声明的Sql Command实例的Parameters集合中添加所有的存储过程调用需要的参数。

(4) 声明Sql Data Adapter和Data Set, 设置Sq Data Adapter的Select Command属性为2中声明的Sq Command实例, 再调用其Fill方法来把返回的行集填充到Data Set中。

(5) 关闭Sql Connection实例。

(6) 释放声明的各个实例。

调用不同的存储过程, 只是第二步的Command Name和第三步中的参数不同。

我们要写一个通用的调用存储过程的方法, 该方法只需要提供要调用的存储过程名字和提供具体的参数值就可实现任何存储过程的调用, 那么就要自动实现如何根据存储过程名来得到它所有的参数信息, 再根据这些参数信息自动创建各个参数。在每个SQL Server数据库中都有自己的系统表。这些系统表被用来保存配置和对象信息。从这些系统表中, 可以得到每个存储过程的所有参数的信息, 其中syscolumns表就保存了包括参数名、类型、长度、方向等需要用到的存储过程的信息。不过, 系统表中的字段会随着SQL Server版本的变化而变化。比如syscolumns中的type和xtype, 它们都保存了类型的信息。要让我们的方法适应SQL Server的版本变化要求, 就要用到信息结构视图。

ANSI-92将信息结构视图定义为一组提供系统数据的视图。利用该视图, 可以将实际系统表在应用程序中隐藏起来, 这样系统表的改变就不会影响到应用程序, 应用程序就可以独立于数据库厂家和版本。

ANSI-92和SQL Server支持用三段命名结构引用本地服务器上的对象。ANSI-92术语称为catalog schema.object, 而SQL Server称为database.owner object。例如, 要找到某个存储过程的所有参数信息, 就用:

那么如何编程实现通用的调用存储过程的方法呢?其部分程序如下:

首先定义两个类:一个是用来作为返回值的载体的, 用一个Data Set返回查询出的数据, 用一个Hashtable返回存储过程的返回值和输出参数;另一个类用来完成声明Sql Connection、Sql Command、Sq Parameter, 创建各个Sql Parameter的功能。

在VB.NET中常用的返回结果集的类为Sql Data Reader和Data Set, 而Sql Data Reader必须在保持连接的状态下才可以使用, Data Set却不需要。在本文的实现方法中, 连接应该在调用之后就断开, 因此采用Data Set来保存返回结果集。

这样用户只需提供存储过程的名字和各个参数值就可以调用存储过程。

摘要:在VB.NET中存储过程的调用模式几乎一样, 不同之处是每个存储过程的参数不同, 所以每调用一次存储过程重复代码很多, 这在做项目时很麻烦。笔者经过实践实现了在VB.NET中调用存储过程的简单方法, 该方法只需要提供要调用的存储过程名字和提供具体的参数值就可实现任何存储过程的调用。

java反射方法调用 篇5

import java.lang.reflect.Method;

import java.lang.reflect.InvocationTargetException;

/**

* Created by IntelliJ IDEA.

* File: TestRef.java

* User: leizhimin

* Date: -1-28 14:48:44

*/

public class TestRef {

public static void main(String args[]) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

Foo foo = new Foo(”这个一个Foo对象!“);

Class clazz = foo.getClass;

Method m1 = clazz.getDeclaredMethod(”outInfo“);

Method m2 = clazz.getDeclaredMethod(”setMsg“, String.class);

Method m3 = clazz.getDeclaredMethod(”getMsg“);

m1.invoke(foo);

m2.invoke(foo, ”重新设置msg信息!“);

String msg = (String) m3.invoke(foo);

System.out.println(msg);

}

}

class Foo {

private String msg;

public Foo(String msg) {

this.msg = msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public String getMsg() {

return msg;

}

public void outInfo() {

System.out.println(”这是测试Java反射的测试类“);

}

}

控制台输出结果:

这是测试Java反射的测试类

重新设置msg信息!

Process finished with exit code 0

Java相关知识点拓展:

Java平台和语言最开始只是SUN公司在1990年12月开始研究的一个内部项目。SUN公司的一个叫做帕特里克·诺顿的工程师被自己开发的C和C语言编译器搞得焦头烂额,因为其中的API极其难用。帕特里克决定改用NeXT,同时他也获得了研究公司的一个叫做“Stealth 计划”的项目的机会。

“Stealth 计划”后来改名为“Green计划”,JGosling(詹姆斯·高斯林)和麦克·舍林丹也加入了帕特里克的工作小组。他们和其他几个工程师一起在加利福尼亚州门罗帕克市沙丘路的一个小工作室里面研究开发新技术,瞄准下一代智能家电(如微波炉)的程序设计,SUN公司预料未来科技将在家用电器领域大显身手。团队最初考虑使用C 语言,但是很多成员包括SUN的首席科学家比尔·乔伊,发现C 和可用的API在某些方面存在很大问题。

工作小组使用的是内嵌类型平台,可以用的资源极其有限。很多成员发现C 太复杂以至很多开发者经常错误使用。他们发现C 缺少垃圾回收系统,还有可移植的安全性、分布程序设计、和多线程功能。最后,他们想要一种易于移植到各种设备上的平台。

资源调用 篇6

A:首先在Word里面正常输入相关的文字信息,接着点击“页面布局”标签中的“稿纸设置”命令。在弹出对话框的“格式”列表中,选择“方格式稿纸”这项。接下来分别设置“行数×列数”和“网格颜色”等选项,最后点击“确定”按钮就可以呈现出需要的效果了。

如何快速给数字添加单位信息

Q:有时我们需要在输入数字的同时,添加一些相关的数字单位信息。如果只是少量的数字,我们可以一个个地输入。如果有大量的数字,一个个添加肯定较慢。那么有没有什么方法可快速添加单位信息呢?

A:首先在单元格里面依次输入相关的数字信息,接着通过配合Ctrl键选中所有的单元格。然后点击WPS表格模块“开始”标签中的“格式”命令,在弹出的菜单里面选择“单元格”命令。接下来在弹出的对话框里面选择“数字”标签,再点击左侧的“自定义”命令,在“类型”输入框输入单位名称即可。

自动套用格式让编辑更加简单

Q:在制作较长的文档以后,需要对文档内容进行编辑,可是很多步骤都是相同的,比如修改字体颜色、字体大小等等。那么通过什么方法可以减轻用户重复的操作步骤呢?

A:通常情况下调用办公软件的“格式刷”,就可以解决用户所遇到的这些问题。首先需要对一段文字信息进行设定操作,设置完成以后点击“开始”标签中的“格式刷”命令,再选择其他的文字信息就可以将格式状态复制过去。需要说明的是,通常格式刷只能使用一次,如果要想重复使用的话,双击“格式刷”命令即可。

如何将PPT中的内容导入Word

Q:现在各种各样的会议都会用到PPT,但是对于很多人来说,PPT中的文字才是最为重要的信息内容。那么如何才可以将PPT中的文字导入到Word文档里面进行使用呢?

A:首先通过软件载入需要的PPT文档,接着点击左上角的软件图标按钮,在弹出的菜单里面选择“另存为”命令。在弹出的保存对话框里面,选择“保存类型”列表中的“大纲/RTF文件”这项,保存成功以后就可以通过Word直接打开运行了。

还有什么软件可以打开dbx文件

Q:老电脑上使用的是Outlook Express 6.0,现在换了新电脑安装的是Office 2010,不再有Outlook Express 6.0软件了。那么如何将以前老的邮件导入到新的Outlook软件里面,毕竟其他软件也打不开dbx格式的文件啊?

C#调用动态链接探析 篇7

从Windows操作系统诞生之日起, 就使用动态链接库 (DLL) 来支持公共函数的调用, 区别于在编译时发生、直接把代码插入到程序EXE文件的静态链接。动态链接是指程序运行时才把自己需要的函数链接进来的代码调用方式, 也就是说只要在应用程序需要时, 才加载DLL到进程的虚拟空间, 成为调用进程的一部分。程序使用DLL的优点包括:一方面, 可以减少在磁盘和物理内存中加载的代码的重复量;另一方面, 也可以促进模块式程序开发和简化程序部署和安装。每种编程语言调用DLL的方法都不尽相同, 本文对用C#调用DLL的方法进行介绍。

1动态链接库 (DLL) 的基本分类

每种编程语言调用DLL的方法都不尽相同, 本文只对用C#调用DLL的方法进行分析总结。首先, 需要了解什么是托管, 什么是非托管。随着.net平台的引入, 代码分为托管代码和非托管代码, 托管代码由公共语言运行库环境 (而不是直接由操作系统) 执行的代码。托管代码应用程序可以获得公共语言运行库服务, 例如自动垃圾回收、运行库类型检查和安全支持等。这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为。非托管代码指在公共语言运行库环境的外部, 由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务;它与托管代码不同, 后者从公共语言运行库中获得这些服务。对于动态链接库DLL来说也分为托管的DLL和非托管的DLL。

2非托管的DLL的C#调用

2.1对于不是基于com的非托管的DLL访问

首先, 应该在C#语言源程序中声明外部方法, 其基本形式是:

[DLLImport (“DLL文件”) ] //-访问DLL文件

修饰符 ReturnType FunctionName (type arg1, type arg2, ...) ;//--声明方法。

其中:DLL文件是包含定义外部方法的库文件。修饰符是除了abstract以外在声明方法时可以使用的修饰符, 一般为public static extern。返回变量类型是在DLL文件中需调用方法的返回变量类型。方法名称是在DLL文件中需调用方法的名称。参数列表是在DLL文件中需调用方法的列表。DllImport还包含了一些可选属性, 其中4个比较常用:

(1) EntryPoint 参数给出 DLL 中入口点的名称。如果未指定 EntryPoint, 则使用方法本身的名称。

(2) CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet, 则使用默认值 CharSet.Auto。

(3) SetLastError 参数指示方法是否保留 Win32“上一错误”。如果未指定 SetLastError, 则使用默认值 false。

(4) CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention, 则使用默认值 CallingConvention.Winapi。

在使用DllImpor时记得引用所在的命名空间System.Runtime.InteropServices, 同时对于不同类型实现的DLL引用的方法也不尽相同。

2.1.1 引用普通winapi中的方法和自己编写的类库中的普通函数方法

采用DllImport的方法直接导入, 如要调用Winapi中的MessageBoxA功能可以:

[DllImport ("user32.dll", EntryPoint="MessageBoxA") ]

static extern int MsgBox (int hWnd, string msg, string caption, int type)

其它参数采用默认值。如果是自己编写的DLL文件中的函数, 一要注意DLL文件所在的位置, 可以放在项目文件夹下的../bin/Debug/目录里或者放在系统目录C:/Windows/system32里;二要注意DLL文件中使用的参数调用方式。C和C++缺省调用方式是_cdecl?, 而系统默认的方式是CallingConvention.Winapi要改为CallingConvention.Cdecl。

2.1.2 引用类库中类的方法和属性

一种是要在C#中调用类库中类的方法, 通过静态方法导出C++中的方法, 在C#中创建同名的类来接受C++中静态的方法, 注意此时C++类中的方法编译后名称改变, 通过dumpbin命令来查看编译后的名称并进行映射;另一种是要在C#中调用类库中类的属性, 主要使用System.Runtime.InteropServices命名空间的Marshal 类的PtrToStructure方法实现DLL中类的创建, 通过创建的类来实现属性的访问。

2.2对于基于COM的非托管DLL的访问

对于非托管代码下基于COM的DLL, 可以先用tlbimp命令将COM类型中定义转换为公共运行时的等效定义。如:TlbImp test.dll /out: test_clr.dll, 在直接在C#项目中添加对test_clr.dll的引用。然后倒入对应的命名空间, 即可访问COM库的类中方法。如果使用 Visual Studio 开发环境, 则只需添加对COM类型库的引用, VS将为您自动完成此转换。

上面使用的TlbImp.exe (类型库导入程序) , 它是一个包括在 .NET 框架 SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET 框架元数据, 从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET 框架元数据可以通过 /R 编译器选项包括在 C# 内部版本中。

注意:在最新的VS2010中直接添加对COM类型库的引用并自动完成此转换后, 要修改DLL的文件引用属性的“嵌入式操作类型”, 由默认的true修改为false, 否则提示无法嵌入互操作类的错误。而在vs2005和vs2008中并无引用属性“嵌入式操作类型”。

3托管的DLL的C#调用

C# 调用托管DLL是很简单的, 只要在“解决方案资源管理器”中的需要调用DLL的项目下用鼠标右击“引用”, 并选择“添加引用”, 然后选择已列出的DLL或通过浏览来选择DLL文件, 最后需要用using 导入相关的命名空间。需要注意的问题也是vs2010中DLL文件引用属性的“嵌入式操作类型”, 也需要由默认的true修改为false。

3.1动态调用托管DLL

C# 动态调用托管DLL也需要借助System.Reflection.Assembly里的类和方法, 主要使用了Assembly.LoadFrom。假如在托管代码的命名空间Test中的Class1类中有Method方法, Method方法有一个int类型参数并返回int的值, 就是假设Method起一个简单的数据处理和返回的作用。编译生成托管的Test.dll文件。在C#项目中要动态引用该DLL, 先导入命名空间:using System.Reflection;在主函数中的调用代码大致如下:

4结语

使用DLL有很多优点, 如:节省内存和减少交换操作;开发大型程序时可以把某些模块分配给程序员, 程序员可以用任何一门所熟悉的语言把该模块编译成DLL文件, 这样可以提高代码的复用, 大大减轻程序员的工作量。所以, 如何灵活地调用DLL应该是每位程序员所熟知的。

本文重点对DLL进行了详细的分类, 对C#访问DLL的方法进行了综合和分析, 提出了调用中要注意的问题。笔者已经在多个项目中使用了上述的访问技术, 提高了工作效率, 缩短了研发周期。

参考文献

[1]潘爱民.COM原理与应用[M].北京:清华大学出版社, 2010.

[2]王小科.C#开发实战宝典[M].北京:清华大学出版社, 2010.

[3]郭新苍, 樊来耀.NET互操作技术研究[J].无线电工程, 2009 (6) .

浅析Linux的系统调用方法 篇8

系统调用是操作系统为用户态的进程与硬件设备 (如CPU、磁盘、打印机等) 之间的交互提供的一组接口。其主要目的是使得用户可以使用操作系统提供的有关设备管理、文件系统、进程控制、进程通讯以及存储管理等方面的功能, 而不必了解系统程序的内部结构和有关硬件细节, 从而起到减轻用户负担和保护系统以及提高资源利用率的作用。以下以Linux系统体系结构为例 (图1) , 分析系统调用的意义。

Linux系统分为三个层次:用户、核心以及硬件。其中系统调用是用户程序与核心间的边界, 通过系统调用进程可由用户模式转入核心模式, 在核心模式下完成一定的服务请求后再返回用户模式。系统调用可以看作是一个所有Linux进程共享的子程序库, 是由内核提供的、功能十分强大的一系列函数。它们在内核中实现, 可以存取核心数据结构和它所支持的用户级数据, 然后通过一定的方式呈现给用户。

2 Linux内核对系统调用的管理

2.1 与系统调用有关的数据结构

为了实现系统调用功能, Linux在内部定义了相关的数据结构。

2.1.1 系统调用响应函数名的约定

函数名以“sys_”开头, 后跟该系统调用的名字, 由此构成238个形如sys_name () 的函数名。例如fork () 的响应函数是sys_fork () 。

2.1.2 系统调用号

通过系统调用号可以找到系统调用表 (sys_call_table) 中对应表项的内容, 它正好就是该系统调用响应函数的入口地址。文件/usr/src/linux-2.4.18-3/include/asm-i386/unistd.h为每个系统调用分配一个唯一的号码。文件中每一行的格式如下:#define __NR_name NNN。其中, name用系统调用名称代替, 而NNN则是该系统调用对应的号码。文件内容如下所示:

#define __NR_exit 1

……

#define __NR_tkill 238

2.1.3 最大系统调用数

在/usr/src/linux-2.4.18-3/include/linux/sys.h中定义的NR_syscalls表示该表能容纳的最大系统调用数, #define NR_syscalls = 256。

2.1.4 系统调用表

系统调用表记录了各个系统调用处理函数的入口地址。通过这张表就可以根据特定系统调用在表中的偏移量, 找到对应的系统调用响应函数的入口地址。系统调用表在文件/usr/src/linux-2.4.18-3/arch/i386/kernel/entry.S中定义, 其中“.”代表当前地址, sys_call_table代表数组首地址, NR_syscalls为系统调用总数。其结构如下所示:

该清单用来对sys_call_table[]数组进行初始化。该数组包含指向内核中每个系统调用的指针。

2.2 系统调用中参数的传递

为使系统调用的执行成为一项简单的任务, Linux提供了一组预处理宏指令, 它们可以用在程序中。这些宏指令取一定的参数, 然后扩展为调用指定的系统调用的函数。在/usr/src/linux-2.4.18-3/include/asm-i386/unistd.h这个头文件中不仅定义了所有的系统调用号, 同时还定义了7个与系统调用有关的宏, 即_syscallN () , N取0~6之间任意数。这些宏用于系统调用的格式转换和参数的传递。

这些宏指令具有类似下面的名称格式:

_syscallN (parameters)

其中N是系统调用所需的参数数目, 而parameters则用一组参数代替。这些参数使宏指令完成适合于特定的系统调用的扩展。例如, 为了建立调用setuid () 系统调用的函数, 应该使用:_syscall (int, setuid, uid_t, uid) 。

_syscallN () 宏指令的第一个参数int说明产生的函数的返回值的类型是整型, 第2个参数setuid说明产生的函数的名称, 后面是系统调用所需要的每个参数, 这一宏指令后面还有两个参数uid_t和uid分别用来指定参数的类型和名称。

另外, 用作系统调用的参数的数据类型有一个限制, 它们的容量不能超过四个字节。这是因为执行int $0x80指令进行系统调用时, 所有的参数值都存在32位的CPU寄存器中。使用CPU寄存器传递参数带来的另一个限制是可以传送给系统调用的数目。这个限制是最多可以传递6个参数。所以Linux一共定义了7个不同的_syscallN () 宏指令, 从_syscall0 () 、_syscall1 () 直到_syscall6 () 。

一旦_syscallN () 宏指令用特定系统调用的相应参数进行了扩展, 得到的结果是一个与系统调用同名的函数, 它可以在用户程序中执行这一系统调用。

2.3 系统调用过程

系统调用的过程如图2所示。其中粗线表示控制流, 细线表示相关数据关系。

(1) 虚框内, 系统处于用户态。用户程序请求系统服务时, 要以C语言函数的形式写一条系统调用命令。假如该命令已在某个.h文件中由相应的_syscallN () 展开, 则用户程序必须include该.h文件。

(2) _syscallN () :当程序执行到此调用时, 实质上是在执行由宏_syscallN () 展开的函数, 它将系统服务请求转换为中断。系统调用的参数由各通用寄存器传递。

(3) 系统执行int $0x80后, 以核心态进入入口地址system_call (代码在entry.S中) 。从system_call入口的汇编程序, 主要执行如下功能:保存寄存器当前值 (SAVE_ALL) ;检验调用是否合法;根据系统调用表sys_call_table[]和寄存器EAX中的系统调用号找到相应的系统调用响应函数并转入执行。当响应函数执行完毕后, 让EAX寄存器保存函数的返回值。这时, 控制转到ret_from_sys_call。

(4) ret_from_sys_call负责恢复现场信息, 将机器从内核态切入到用户态, 继续执行中断的程序。

3 在Linux中添加新的系统调用

添加新的系统调用可以通过两种方式实现, 一是通过修改内核源代码, 二是利用Linux内核模块。通过修改内核源代码的方式, 将新的系统调用直接静态编译成内核的一部分, 这样会增加内核的大小, 还要改动内核的源文件, 而且不能动态地卸载, 不利于调试;利用Linux内核模块的方式, 则是将新的系统调用编译成可以动态加载的模块, 所以推荐使用模块方式。

3.1 通过修改内核源代码添加系统调用

用户在Linux中添加新的系统调用, 可以遵循几个步骤才能添加成功, 下面几个步骤详细说明了添加系统调用的相关内容。

3.1.1 添加源代码

第一个任务是编写加到内核中的源程序, 即将要加到一个内核文件中的函数, 该函数的名称应该是新的系统调用名称前面加上sys_标志。假设新加的系统调用为mycall () , 在/usr/src/linux-2.4.18-3/kernel/sys.c) 文件中添加源代码 (作为一个最简单的例子, 新加的系统调用仅仅返回一个整型值) , 如下所示:

3.1.2 连接新的系统调用

添加新的系统调用后, 下一个任务是使Linux内核的其余部分知道该程序的存在。为了从已有的内核程序中增加到新的函数的连接, 需要编辑两个文件。

第一个要修改的文件是/usr/src/linux-2.4.18-3/include/asm-i386/unistd.h。根据unistd.h文件查看Linux内核自身的系统调用号码已经用到238, 而sys.h文件中显示最大系统调用号为256, 因此新的系统调用号可在239~256之间, 可设定为:#define __NR_mycall 239。

第二个要修改的文件是:/usr/src/linux/arch/i386/kernel/entry.S。在相应位置添加.long SYMBOL_NAME (sys_mycall) , 这样就在sys_call_table[]数组中增加了新的内核函数的指针。

3.1.3 编译内核, 重启动系统

通过编译内核, 重建新的Linux内核, 让新添加的系统调用成为操作系统的一部分。然后用新内核启动系统, 这样用户就可以在应用程序中使用该系统调用了。

3.1.4 使用新的系统调用

与新的内核模块运行于内核态不同, 调用新的系统调用是在用户进程中进行并运行于用户态的。相应的, 调用新的系统调用所在的程序段只需在用户态下编译即可生成可执行文件。在应用程序中使用新添加的系统调用mycall。同样为实验的目的, 写了一个简单的例子exam.c。

3.2 利用Linux内核模块添加系统调用

3.2.1 编写内核模块

编写新的内核模块有比较固定的格式, 对应的具体程序段由以下三部分组成。第一部分是新的内核函数, 这个函数体中的代码明确了添加到内核中的模块所能完成的功能。第二部分是模块初始化函数 (init_module () ) , 主要用于初始化参数、系统注册、修改系统调用表等。第三部分是卸载模块时所调用的函数 (cleanup_module () ) , 这个函数将恢复初始化函数中修改的内容, 如卸除系统注册、恢复系统调用表等。

以下给出一个内核模块的编写实例 (mker.c) , 这个实例的组成如上所述。mker.c源程序内容如下。

3.2.2 编译新的内核模块

编写新的内核模块之后, 要对这个源文件进行编译。内核模块的编译需要用到一些选项, 以指明用哪种方式编译、最终的代码运行于哪种模式下等。具体操作为, 在命令行下键入gcc –Wall –DCONFIG_KERNELD –DMODULE –D_KERNEL_-DLinux –c mker.c。其中, –Wall选项是要求gcc将所有的警告信息显示出来;后面几个以D开头的选项则指明了编译出的代码运行在内核模式下。注意, 以这种方式编译出的不是可执行文件, 而是二进制模块文件mker.o。

3.2.3 加载和卸载新的内核模块

得到mker.o文件之后, 就可以将模块加载到内核中, 以供用户通过系统调用的形式调用该模块所加载的函数。可使用insmod命令手工把它加载到核心 (即在命令行键入insmod mker.o) 。insmod命令在/lib/modules/kernel-version目录的modules.dep文件里找到它要加载的被请求的核心模块, 然后进行加载。在模块被加载之后, 可以用命令lsmod列出所有加载的核心模块和它们之间的依赖关系, 以检查是否所需模块已加载在内核中。

当内核中的模块不再使用时就需要对其卸载, 以免它占用内存空间。模块可以用rmmod命令卸载 (即在命令行输入rmmod mker, 注意这里不带.o后缀) 。

3.2.4 使用系统调用

在编写好新的内核模块、将它加载到内核, 并且做好了新的系统调用之后, 我们就可以对这个新的系统调用在用户进程中进行具体的调用。以下为使用新添加的系统调用的程序段 (callsys.c) , 这个程序调用mycall () 函数来计算值, 并在终端输出。

3.2.5 系统调用工作流程

结合以上例子, 可将系统调用的工作流程总结如下:

当程序调用mycall () 这个函数时, 便会调用第三行, 通过查看头文件unistd.h中宏syscall2的定义, mycall () 会被展开成以下代码:

从中可以看出, 程序通过调用宏__NR_mycall得到调用号, 放到寄存器eax中, 同时将参数num1、num2放入通用寄存器ebx、ecx中, 接着执行中断指令“int $0x80”。这样就陷入到内核中, 根据系统调用号索引sys_call_table, 并找到最终的内核函数sys_mycall () , 这个内核系统调用函数仅返回计算得到的值, 将返回值送入CPU的eax寄存器中, 最后进程返回到用户态, 用户程序最终执行完成, 整个系统调用过程也就完成。

3.3 两种方式对比

通过修改内核源代码的方式, 将新的系统调用直接静态编译成内核的一部分, 这样会增加内核的大小, 还要改动内核的源文件, 而且不能动态地卸载, 不利于调试。

而利用Linux内核模块的方式, 则是将新的系统调用编译成可以动态加载的模块, 使用非常灵活, 所以推荐使用模块方式。

4 总结

综上所述, 由于Linux操作系统的自由开放性及容纳用户自定义系统调用的特性, 我们完全可以在原有系统调用的基础上, 添加一些有益的、实用的新的系统调用功能, 让Linux操作系统为我们提供更多更好的服务。

摘要:系统调用是连接应用程序和系统内核的关系纽带, 本文以RedHat Linux2.4.18为例, 通过对Linux操作系统中系统调用数据结构、参数传递、调用过程的分析, 提出了两种实现系统调用的方式, 并提供了详细代码。

关键词:Linux操作系统,系统调用,内核模块

参考文献

[1]陈莉君, 康华.Linux操作系统原理与应用.北京:清华大学出版社, 2006:133-148.

[2]陈刚, 卢显良.基于Linux-2.6内核模块程序设计.福建电脑, 2004, (6) :15-16.

资源调用 篇9

(1)句柄。句柄是Windows系统用来标识对象的唯一整数,许多API函数需要句柄作为参数。通常,句柄用小写“h”开头,如hWnd表示窗口句柄,hDC表示设备场景句柄。在PB中,可以通过其handle函数来取得窗口或控件的句柄,当声明API函数时,常把句柄变量声明为Long或uLong长整型数据类型。

(2)设备场景。设备场景(DC)是一组由Windows系统定义的数据结构对象,结构对象定义了与绘图有关的一组图形和属性。在Windows系统中有四类DC,分别是显示、打印、内存和信息。DC是一种虚拟对象,PB不能直接获得,只能通过使用GetDC外部函数取得,比如,想要获取指定窗口的DC,须利用PB内部函数handle取得窗口的句柄hWnd,并将窗口句柄hWnd作为参数传给外部函数GetDC。需要注意的是,如果调用了GetDC函数,当操作指令结束后,需调用ReleaseDC API函数来释放内存资源。

2 PB API函数的语法格式

在PB中使用API外部函数之前,须首先进行声明。用户可以用两种方式来声明API函数。

(1)全局级API函数。可在应用程序的任意位置调用。

(2)对象级API函数。只能在窗口、菜单、用户对象等对象的内部调用。

外部函数的声明以两个关键字FUNCTION或SUB-ROUTINE为起始。如果函数所表达的过程有返回值,则应将其声明为FUNCTION,其语法如下:

如果函数表达的过程无返回值,则应将其声明为SUB-ROUTINE,其语法为:

在PB的声明中,大括号中的内容是可选的。声明中的其它各关键字作用如下:

Access:函数的访问级别,默认为Public,此参数只能在对象级外部函数中使用。

ReturnDataType:函数的返回值的数据类型,须与PB所支持的数据类型相匹配。

Functioname/Subroutinename:函数或过程的名称。名称可以由用户自定义,但如果与动态库内部函数名称不一致,则必须通过Alias For子句给出动态库中函数或过程的真正名称。

REF:标明变量通过引用方式传递。DataType:外部函数中参数的数据类型。Arg:外部函数的参数名。LibName:所要引用的动态库DLL或EXE的文件名。Externa|Name:表示DLL库中的外部函数或子程序名。

3 C数据类型与PB数据类型的转换

在MSDN中,API函数均为C语言格式,其数据类型也是完全按照C语言的格式进行定义的,这些数据类型与PB的使用格式存在一定的差异,需要进行转换。表1列出了API函数的C原型与PB相应数据类型的关系。

4 PB与API函数之间的参数传递

调用Windows系统动态库的函数时,大部分函数需要传入一个或多个参数。参数的传递方式可以是值传,也可以是引用传递。默认情况下,PB调用DLL中的函数是通过传值方式来进行的,也就是说PB将对要传递的参数做一份复制,然后通过堆栈将这份复制传递给外部函数,外部函数对其参数的任何修改不会影响到PB参数的原值。如果希望DLL中的函数来改变调用参数的原值,可通过引用方式来传递参数,即在参数数据类型前面加REF关键字来声明。通过引用方式传递参数,外部函数得到指向其参数的指针,外部函数可对其参数的值进行修改,并将修改后的结果回传PB中。需注意的是,在声明PB外部函数时,是否加关键字TRF,须根据MSDN对函数的定义,而不能随意添加。

5 PB调用API应注意的事项

(1)确保函数参数的正确性。在Windows环境中,16位和32位数据变量都可能按32位传递,当这些数据同时使用时很难发现其中的错误。

(2)有些API函数对大小写敏感。虽然PowerScript对大小写不敏感,但API函数却例外,比如,“FindWindowA”能正常工作,而“Findwindowa”可能会报错。

(3)合理分配全局级API函数与对象级API函数。虽然全局级API函数可以在程序的任意位置调用,但其占用的资源较多。应根据程序开发的最低需要,尽可能把API函数声明在对象级。另外,应及时释放使用过的内存资源,防止因申请内存资源失败而死机。

参考文献

[1]马贵安,李明武,牛永生.PowerBuilder Win32API函数调用参考手册[M].北京:清华大学出版社,2004.

[2]PB API调用原型.PB技术.http://www.procedurelife.com/techn-ical/PB/content/lebdl.html.

表格法辅助阅读递归调用程序 篇10

在递归调用程序中,比较容易阅读的是求解数学上阶梯函数的递归调用程序。首先在程序中找到递推语句、递归结束条件及递归结束时的值,根据递推语句一步一步递推,直到条件成立获得递归结束时的值,使递推结束;然后一步一步回归,即可求得函数的值。递推的轨迹和回归的轨迹都比较清晰。若递推语句之后还有赋值语句或输入输出语句等,则递推的每一步要将许多参数压栈,回归的每一步又要根据先前压栈的相关参数确定若干变量的值,程序阅读起来就比较复杂。使学生能顺利正确地阅读这类程序是教学难点之一。教学实践表明,在阅读递归调用的程序时引入表格法,可以使学生感觉有方法可依,能够按部就班地阅读程序,克服畏难情绪,也能够有效防止出错。越是阅读复杂的递归调用程序,表格法越是能显示其有效作用。本文以一道Visual Basic二级考试题为例,介绍怎样采用表格法辅助阅读递归调用程序。

例题如下:运行下面的程序,单击命令按钮Command1,则在窗体上显示的第一行内容是____,第二行内容是___,最后一行内容是_____。

1. 通读程序找出递推语句和递推结束语句

在本例中,程序由主过程Command1_Click()和函数过程Recursion%(A%,B%)构成。在主过程中从“Lcm=Recursion (N, M)”语句开始调用函数过程Recursion%(A%,B%)。函数过程Recursion%(A%,B%)以A、B为形式参数,采用传址调用。“Recursion=2*Recursion (A+A/k, B)”语句为递推语句。“A Mod B=0”是递推结束的条件,“Recursion=A”语句是递推结束语句。程序执行过程中,只要“A Mod B=0”条件不为True,就使递推语句“Recursion=2*Recursion (A+A/k, B)”执行一次,直到“A Mod B=0”条件为True,执行“Recursion=A”语句,递推才结束。

2. 用表格演绎递推过程

表一是为阅读递归调用程序而设计的表格,其横向从左向右表示递推的步骤,每一列表示递推一步,即调用自身一次;纵向依序是程序执行语句中的表达式。表格的含义就是每递推一步,程序中各表达式依照其顺序应该获得什么值。在阅读程序时,程序的阅读者首先应该按照程序语句执行的顺序将各个表达式填入表格,然后开始逐步递推。在递推过程每一步中,要填写递推步骤序号,填写在本步递推中各个表达式获得的值。对于本例而言,因为“A Mod B=0”是递推结束条件,当在某一步中A与B的值相等时,表明该步骤是递推的最后一步了。从已填的表格可见,在递推结束之前,递推结束条件“A Mod B=0”在每一步均为False,因此执行“Recursion=2*Recursion (A+A/k, B)”语句。而“Recursion=2*Recursion (A+A/k, B)”语句并不能立即获得具体的值,要用“A+A/k, B”作为实际参数调用Recursion%(A%,B%)函数一次。当递推结束条件“A Mod B=0”的值为True, Recursion获得值64,即获得参数A的值,递推结束。在递推结束后,程序要向下执行语句“Print 2*A, k”和“k=k-1”,开始回归。因此,在递推的最后一步,程序阅读者还应该填写表达式“2*A, k”和“k”的值。

3. 用表格演绎回归过程

在表一的下方再增加一行,从右向左表示回归的步骤,如表二所示。在本例中,回归的每一步做三件事:(1)根据得到的Recursion值计算“2*Recursion”的值并赋值给Recursion自身;(2)执行“Print 2*A, k”语句;(3)执行“k=k-1”语句。表格中后三栏分别记录“2*Recursion”、“2*A, k”、“k”三个表达式在回归的每一步中所获得的值。因此,在回归的每一步中,程序阅读者应该做的事情是分别填写表达式“2*Recursion”、“2*A, k”、“k”的值。

4. 根据表格答题

程序阅读者根据所填的表二,就可以进行答题工作,即填写题目所留的空格。依据程序,在窗体上显示信息是由函数过程中的语句“Print 2*A, k”和主过程中的语句“Print“Lcm=”;Lcm”完成。“Print 2*A, k”语句在回归的每一步中执行一次,显示一行信息,即表达式“2*A, k”的值,共显示四行。主过程中的语句“Print“Lcm=”;Lcm”执行一次,在窗体上显示的信息为第五行。

因此,在窗体上显示的第一行内容是,第二行内容是,最后一行内容是。

5. 结语

本文为参加Visual Basic二级考试的学生阅读递归调用程序提供了一种有效的方法,这种方法能够有效地阅读复杂的递归调用程序,防止出错。使用这种方法达到熟练以后,在阅读递归调用程序时不一定要画出表格,可以在程序的旁边根据递推与回归的步骤,按行按列依序写出各个表达式的值,但要做到心中有表。

参考文献

[1]龚沛曾, 杨志强, 陆慰民.Visual Basic程序设计教程[M].北京:高等教育出版社, 2007.

发挥教师的协调用构建理想的课堂 篇11

音乐学科是人文学科的一个重要领域,是实施美育的主要途径之一,是基础教育阶段一门必修科。随着音乐课程改革的实施和深入,音乐教师对“教师”观念的更新和教学中教师与学生角色的转变,以及过去以教师和教材为中心的传统教学模式和评价方式,正逐渐被摒弃。许多音乐教师在音乐教学中运用《音乐课程标准》中的理念,使教师的教学方式有了较大突破,学生的学习发生可喜的变化,取得了良好的教学效果,极大提高了学生学习音乐的兴趣,使音乐教学焕发出勃勃生机。然而有部分音乐教师对《音乐课程标准》的理念和要求认识不全面、把握不正确,因而在课堂教学中出现了某些偏差,甚至走入了与课程标准相悖的误区。进入21世纪以来,音乐学科作为素质教育的一个重要的组成部分,对于培养学生创新精神和实践能力有着不可忽视的作用。新修定的“中学音乐教学大纲”明确要求在音乐教育中教师应采用多种形式引导学生积极参加音乐实践,所以,教师要做好协调人,在课堂上多鼓励学生对所听音乐有独立的感受和见解,并勇于表述自己的体验。而学生的研究性学习以其自身的开放性、探究性、实践性和过程性正适应了这种要求。教师多引导学生通过音乐研究性学习,协调学生的综合知识、综合能力得到提高,实践能力和创新能力得到培养,这样就弥补了传统教学模式重知识传授、轻能力培养的缺陷。

一、音乐课堂中突出研究性学习的意义

(一)通过研究来了解相关的音乐文化知识

学生在一起研究课题的过程中,不仅要协调他们欣赏音乐的态度、习惯、审美创新能力等方面得到了有效提高,还能不自觉的获取许多相关的音乐文化知识。如在了解通俗音乐发展史的同时,了解到早期的通俗音乐大致起源公元前古罗马,古埃及的行吟歌手们在兴起的城市集镇间流动,遍及剧场和街市的“击”歌现象,在学生学习知识同时,及时联想到在文学中所说的我国古时候吟诗也如同唱歌,甚至有同学提出中国的最早的通俗音乐是否就是宋朝柳永的一些词——“凡有井水处,皆有柳郎词”。通过这样的协调学习,学生对本国和世界各国一些不同民族的文化有了了解,对各类艺术形式的共性和个性也有所认识

(二)通过研究使学生感触美,渲染美

在音乐课教学中,有好多教材内容是很好的美的教育,美得熏陶。这些内容通过教师的协调引导,才能使学生受到美好的教育。所谓感触美,渲染美是审美、创美的首步。从小学到中学,音乐教材是一个极富魅力的“美”的世界。在这个“美”的音乐世界里,从丽日皓月,繁星流云到江河湖海的歌颂;又到大地山川自然景色的赞美;从讴歌、咏叹浴血刑场、坚贞不屈的革命烈士的颂扬;到“鞠躬尽瘁,死而后已”的英雄人物形象的赞美。从这些塑造的音乐形象中,引导学生充分感触美,认真渲染美,每节课都要充分发挥教师的协调作用,运用灵活多样的教学方法,不管欣赏课还是唱歌课,都能运用这些优秀的艺术作品,表达人类的信念、理想、报负与情感,是心灵之声。通过欣赏、歌唱、赞美的教学。使学生在美的海洋里遨游,探索人生的内在需求,不仅使学生的心灵和情操得以陶冶,而且使学生在美的欣赏研究作品中,理解音乐和鉴赏音乐的能力。增强表现美的能力,最终达到美的教育。

二、整合学科本体,做好协调人

随着我国新一轮基础教育课程改革的启动,我们清晰地看到,包括音乐在内的各门学科都把加大学科联系,实现多学科渗透作为一个重要的课程理念来落实。《音乐课程标准》中就明确提出“提倡学科综合”的理念,包括音乐教学与不同领域之间的综合,音乐与舞蹈、戏剧、影视、美术等姊妹艺术的综合;音乐与艺术之外的其他学科的综合。“学科综合”丰富了音乐学科的人文蕴含,加深了学生对音乐的理解、感受和体验,有利于拓展学生的视野,提高学生的综合能力和个体的和谐发展。但我们要清楚地看到,音乐的综合性学习,是基于音乐学科本身的特点和人的全面发展的需要,是以音乐为本的综合。有的教师对“综合”的内涵没有真正理解,以为“综合”是以学科知识技能的简单相加而成,甚至有的教师为体现综合,竞撇开音乐的学科特点,把音乐课上成了政治课、社会课或其他课程。虽貌似综合,其实只是形式上的伪综合,从而出现了“学科综合”不合理,忽视音乐本体的误区。

总之,在音乐教学中学生学习兴趣的激发、想象创造能力的培养和审美能力的发展,都需要教师做好协调人,创设一个自然、愉悦、美好的学习情境。使学生在轻松、愉悦的环境中受其音乐的感染,通过对美得音乐的欣赏、对美的音乐学习得到心灵和情操的陶冶,使他们在音乐学习中,增强理解音乐感受音乐的能力,也发展了他们的形象思维能力和智力,培养了对音乐的兴趣和爱好,提高了自身的音乐素养。

基于RMI的Java远程调用 篇12

在现实生活中, 随着企业信息化建设的不断深入和发展, 企业自己内部和不同企业之间对信息以及对数据的相互之间交换量越来越大, 而这些数据以及信息往往大都需要在不同的计算机网络间传送和交流, 分布式计算可以通过调动不同网络上多台计算机的计算处理能力, 发挥远程调用数据的功能。 RMI (Remote Method Invocation) 是一种分布式技术, 使用RMI可以让一个虚拟机 (JVM) 上的应用程序请求调用位于网络上另一处的JVM上的对象方法。 习惯上称发出调用请求的虚拟机 (JVM) 为 (本地) 客户机, 称接受并执行请求的虚拟机 (JVM) 为 (远程) 服务器[1]。 RMI应用程序通常包括两个独立的程序, 服务器程序和客户机程序。 典型的服务器应用程序将创建多个远程对象, 使这些远程对象能够被引用, 然后等待客户机调用这些远程对象的方法。 而典型的客户机程序则从服务器中得到一个或多个远程对象的引用, 然后调用远程对象的方法。 RMI为服务器和客户机进行通信和信息传递提供了一种机制[2]。

2 远程对象及其代理

2.1 远程对象

驻留在 (远程) 服务器上的对象是客户要请求的对象, 称为远程对象。 也就是客户程序请求远程对象调用方法, 然后远程对象调用该方法并返回结果[3]。

2.2 代理与存根

使用RMI, 客户应用程序不需要与远程对象直接打交道, 而让客户应用程序和远程对象的代理打交道, 远程对象与远程对象的代理都实现了相同的接口。 当用户请求远程代理调这样的方法时, 一旦远程代理确认远程对象能调用相同的方法, 远程代理就会把实方法调用委派给远程对象。 RMI会给用户生成一个叫存根 (Stub) 字节码, 同时把这个存根产生的对象为作为远程对象的代理[4]。 远程代理对象需要驻留在客户端, 所以需要把存根下载或者复制到 (本地) 客户机。 因此, 用户实际上是在和远程对象的代理直接打交道, 但用户并没有感觉到他在和一个代理打交道, 而是觉得自己是在和远程对象直接打交道, 如图1 所示

2.3 Remote接口

RMI为了标识一个可以被客户请求的一个对象是远程对象, 要求远程对象必须实现java.rmi包中的Remote接口, 只有实现了Remote接口的类的实例才能够被RMI认为是一个远程对象。 Remote接口中没有方法, 因此必须扩展Remote接口, 以便规定远程对象的哪些方法是客户可以请求的方法, 用户不用编写和远程代理的相关代码, 只需知道远程对象和远程代理实现了相同的接口即可[5]。

3 RMI的设计过程

假设C:Client目录用来存放本地客户端的相关类; 远程服务器的有关类的存放目录是C:Server, 同时服务器的IP地址是127.0.0.1。

3.1 扩展Remote接口

定义一个接口是Remote的子接口, 即扩展Remote接口。以下方法定义一个Remote的子接口Sub Remote。 该子接口中定义了一个求面积的方法, 即要求远程对象为用户计算某种图形的面积, 其代码如下:

将该接口保存在远程服务器的C:Server目录中, 同时并编译它生成相应的.class目标字节码文件。 因为客户端的远程代理也需要使用到该接口, 所以该目标字节码文件生成后复制一份到C:Client客户端的目录中。

3.2 创建远程对象

RMI使用Remote接口来标识一个远程对象, 而Remote接口中并没有方法, 所以需要创建远程对象的类实现Remote接口的一个子接口。 同时, RMI为了让一个对象成为远程对象, 还需要进行一些必要的初始化工作, 因此在创建远程对象的类时, 可以让该类是RMI提供的java.rmi.server包中Unicast Remote Object类的子类。 以下创建远程对象的类Con SubRemote实现了上述Sub Remote接口, 所创建的远程对象可以计算圆的面积:

将Con Sub Remote.java保存到远程服务器的D:Server目录中, 并编译它生成.class目标字节码文件。

3.3 生成存根

RMI负责产生存根, 如果创建远程对象的字节码是Con SubRemote.class, 哪么存根字节码是Con Sub Remote_Stub.class。 RMI使用rmic命令生成存根Con Sub Remote_Stub.class, 首先进入C:Server目录, 然后执行如图2 所示rmic命令, 即可生成存根。

生成存根后, 客户端可使用存根来创建远程代理对象, 所以需要将Con Sub Remote.class复制到C:Client客户端的目录中。

3.4 启动注册rmiregistry

创建远程对象, RMI要求远程服务器必须先启动rmiregistry, 启动了rmiregistry, 远程服务器才能够创建远程对象, 并将该创建的远程对象注册到rmiregistry管理的注册表。 在远程服务器执行rimregistry命令。 就可以启动注册rmiregistry。

3.5 启动远程对象服务

启动rmiregistry后, 远程服务器就可以启动远程对象服务了。 远程服务器使用java.rmi包中的Naming类调用其类方法rebind绑定一个远程对象到rmiregistry所管理的注册表中。

rebind (String name, Remote obj)

rebind方法中的参数name是URL格式, 参数obj表示远程对象, 客户端的代理可以通过name找到远程对象obj。 运行以下程序Remote Bind, 该程序可以启动远程对象服务, 即该应用程序可以让用户访问它注册的远程对象。

将Remote Bind.java保存到远程服务器的D:Server目录中, 并编译它生成相应的Remote Bind.class字节码文件, 然后运行Remote Bind。

3.6 运行客户端程序

远程服务器启动远程对象服务后, 客户端就可以运行有关程序, 访问使用远程对象了。 客户端使用java.rmi包中的Naming类调用其类方法Lookup (String name) , 调用该方法返回一个远程对象的代理, 即使用存根产生一个和远程对象具有同样接口的对象, 该方法中的参数name的取值必须是远程对象注册的name[6]。 如rim://127.0.0.1/rect。

客户程序可以像使用远程对象一样来调用Lookup (String name) 方法返回远程代理。 如下面的客户应用程序Client Application中的代码就调用了Lookup方法返回一个实现Sub Remote接口的远程代理。

Client Application.java保存到客户端D:Client目录中, 上述Client Application程序使用远程代理计算圆的面积, 然后编译、 运行该程序即可以使用远程代理计算圆的面积, 程序运行效果如图3 所示。

4 结语

RMI是一种分布式技术, 使用RMI可以让一个虚拟机上的应用程序请求调用位于网络上另一处JVM上的对象方法, 它可以简化在多台计算机上的Java应用之间的通信, 可以在编程时不必再过问在RMI之下的网络细节问题, 任意两台计算机之间的通信完全由RMI负责, 这样可以简化程序开发编写工作, 提高效率。

摘要:在Java程序开发中, 经常会在网络开发编程中涉及到Socket (套接字) 编程, 但使用Socket进行网络编程需要大量重复编码, 在比较复杂分布式操作时, 将会使设计过程显得非常麻烦, 而且十分容易出现错误。提出使用RMI实现Java的远程调用, RMI是分布式对象软件包, 是一种分布式技术, 它可以简化在多台计算机上的Java应用之间的通信, 可以在编程时不必再过问在RMI之下的网络细节问题, 任意两台计算机之间的通信完全由RMI负责, 这样可以简化程序开发编写工作, 提高效率。

关键词:RMI软件包,Java语言,Socket编程,远程调用

参考文献

[1]李芝兴, 杨瑞龙.Java程序设计之网络编程基础教程[M].北京:清华大学出版社, 2012.

[2]张思民.Java语言程序设计[M].3版.北京:清华大学版社, 2015.

[3]朱喜福.Java网络编程[M].2版.北京:人民邮电出版社, 2008.

[4]王诚, 梅霆.Java编程技术与项目实战[M].2版.北京:人民邮电出版社, 2015.

[5]孙宪丽, 关颖.Java程序设计基础与实践[M].北京:清华大学出版社, 2015.

上一篇:3+2分段培养下一篇:乡镇工程