一种可移植软件的设计方案
发布时间:2008/6/5 0:00:00 访问次数:221
引言
在当今的软件设计中,为了在不同的产品线上重复使用相同的代码,需要将代码从一个平台移植到另一个平台。虽然这种代码的重复利用非常重要,但是很少有人讨论该采用何种方法来减少设计可移植软件的成本,本文将介绍一种可行的设计方案。
可移植代码的重要性
过去,嵌入式应用程序一般不需要运行在不同的硬件平台和不同的操作系统上,因此开发者也不需要考虑让代码运行到多平台上的问题。
随着技术的发展,市场竞争的激烈,厂家必须不断开发新产品。如果是需要为新产品重新设计新软件,一来开发周期长,另一方面,代码要经过严格测试后才能推出,就会影响产品的面市时间。因此,将已有的、已经过测试的代码移植到新产品上就是一个很好的办法,进而开发者被要求
设计出可运行在不同硬件平台或不同操作系统下的应用程序。但是,由于系统设计可选择不同的设备、不同的子系统以及cpu,范围非常广泛,这样的不确定性势必会增加开发多平台软件的难度。
使用抽象层设计可移植代码
抽象层的先进之处在于它能够提取应用程序的基本内容,并将其与系统实现相隔离。这里关键是要将应用程序的逻辑算法与其运行环境相隔离。例如,在读取文件时,应用程序应该只关心文件的内容,而不在意文件是存在于fat文件系统中,还是ext2文件系统中;在数据通信中,通信双方应该只关心收发的数据本身,至于数据传输的媒体则不是应用程序该考虑的。
多平台软件的系统构成如图1所示,这种方法可广泛地应用在各种应用程序中。就像系统的机械组件可以被抽象,通信接口、cpu资源、存储设备等也可以被抽象。灵活使用抽象层可以将应用程序简化为一个紧凑并可重复利用的代码。
操作系统函数永远不要被直接调用,应将其包装到一个“操作系统抽象层”的库中,把应用程序从底层的操作系统中脱离出来。于是,当将应用程序移植到其他操作系统时,只要简单地移植操作系统抽象层即可,无需修改应用程序的代码。 这不仅将原应用程序的正确性和可靠性带到了新平台上,还加速了移植过程。此外,当在向新平台移植的过程中发现错误时,操作系统抽象层将是调试的最有效的起点。
操作系统抽象层应该输出函数原型,同时,不管底层的操作系统是如何实现的,抽象层应该对应用程序隐藏它们的一些特殊行为。例如,拿对信号量的操作来说,在大多数操作系统中,相同的进程可以多次获取一个信号量,而某些操作系统在递归获取信号量时会阻塞调用者。这里假设操作系统抽象层库输出一个信号量获取函数os_semtake(),那么它必须禁止该系统的标准操作,完成通用信号量获取的功能,使该函数独立于底层的操作系统。在递归获取信号量这个例子中,开发者必须实现递归行为本身。具体实现中,一些操作系统可能要比较两个任务的id,这两个任务一个是上次要求获取信号量的任务,另一个是本次要求获取信号量的任务。如果两个id相同,说明是在同一进程中,函数将增加信号量的计数器,且不调用操作系统的信号量获取函数。相应的,信号量释放函数必须对信号量的计数器进行递减操作,直到计数器为0,才调用操作系统程序中编写的函数封装应该保证在所有的操作系统中具有相同的行为,这可以避免底层操作系统的特殊性对应用程序的影响。
socket库函数中的select()提供了一个很好的例子来说明函数封装的重要性。对于不同的操作系统来说,可选择的设备有相当大的差异,一些系统只允许选择插口,而其它系统可以选择插口、管道和消息队列。在移植过程中,对底层操作系统实现的抽象使应用程序免于不必要的、杂乱的修改。如果某个操作系统没有实现select()的超时功能,只要在抽象层库中就能够完成修改。否则,就需要对应用程序的结构进行重大修改。
逻辑接口
这一步需要将物理接口转换为逻辑接口。比如一个系统中所有的外围设备都连接到一个总线上,那么就可以建立一组访问总线的函数,例如读总线数据函数busreadfrom()、向总线发送数据函数bussendto()等,这可以有效地将
总线操作从应用程序中提取出来。这样,无论总线是用pci、vme、串口或其它形式实现,都可使用逻辑接口将应用程序与物理接口隔离开。
逻辑接口特
在当今的软件设计中,为了在不同的产品线上重复使用相同的代码,需要将代码从一个平台移植到另一个平台。虽然这种代码的重复利用非常重要,但是很少有人讨论该采用何种方法来减少设计可移植软件的成本,本文将介绍一种可行的设计方案。
可移植代码的重要性
随着技术的发展,市场竞争的激烈,厂家必须不断开发新产品。如果是需要为新产品重新设计新软件,一来开发周期长,另一方面,代码要经过严格测试后才能推出,就会影响产品的面市时间。因此,将已有的、已经过测试的代码移植到新产品上就是一个很好的办法,进而开发者被要求
使用抽象层设计可移植代码
抽象层的先进之处在于它能够提取应用程序的基本内容,并将其与系统实现相隔离。这里关键是要将应用程序的逻辑算法与其运行环境相隔离。例如,在读取文件时,应用程序应该只关心文件的内容,而不在意文件是存在于fat文件系统中,还是ext2文件系统中;在数据通信中,通信双方应该只关心收发的数据本身,至于数据传输的媒体则不是应用程序该考虑的。
多平台软件的系统构成如图1所示,这种方法可广泛地应用在各种应用程序中。就像系统的机械组件可以被抽象,通信接口、cpu资源、存储设备等也可以被抽象。灵活使用抽象层可以将应用程序简化为一个紧凑并可重复利用的代码。
图1 多平台软件系统构成图
操作系统抽象层
操作系统抽象层应该输出函数原型,同时,不管底层的操作系统是如何实现的,抽象层应该对应用程序隐藏它们的一些特殊行为。例如,拿对信号量的操作来说,在大多数操作系统中,相同的进程可以多次获取一个信号量,而某些操作系统在递归获取信号量时会阻塞调用者。这里假设操作系统抽象层库输出一个信号量获取函数os_semtake(),那么它必须禁止该系统的标准操作,完成通用信号量获取的功能,使该函数独立于底层的操作系统。在递归获取信号量这个例子中,开发者必须实现递归行为本身。具体实现中,一些操作系统可能要比较两个任务的id,这两个任务一个是上次要求获取信号量的任务,另一个是本次要求获取信号量的任务。如果两个id相同,说明是在同一进程中,函数将增加信号量的计数器,且不调用操作系统的信号量获取函数。相应的,信号量释放函数必须对信号量的计数器进行递减操作,直到计数器为0,才调用操作系统程序中编写的函数封装应该保证在所有的操作系统中具有相同的行为,这可以避免底层操作系统的特殊性对应用程序的影响。
socket库函数中的select()提供了一个很好的例子来说明函数封装的重要性。对于不同的操作系统来说,可选择的设备有相当大的差异,一些系统只允许选择插口,而其它系统可以选择插口、管道和消息队列。在移植过程中,对底层操作系统实现的抽象使应用程序免于不必要的、杂乱的修改。如果某个操作系统没有实现select()的超时功能,只要在抽象层库中就能够完成修改。否则,就需要对应用程序的结构进行重大修改。
逻辑接口
这一步需要将物理接口转换为逻辑接口。比如一个系统中所有的外围设备都连接到一个总线上,那么就可以建立一组访问总线的函数,例如读总线数据函数busreadfrom()、向总线发送数据函数bussendto()等,这可以有效地将
逻辑接口特
引言
在当今的软件设计中,为了在不同的产品线上重复使用相同的代码,需要将代码从一个平台移植到另一个平台。虽然这种代码的重复利用非常重要,但是很少有人讨论该采用何种方法来减少设计可移植软件的成本,本文将介绍一种可行的设计方案。
可移植代码的重要性
过去,嵌入式应用程序一般不需要运行在不同的硬件平台和不同的操作系统上,因此开发者也不需要考虑让代码运行到多平台上的问题。
随着技术的发展,市场竞争的激烈,厂家必须不断开发新产品。如果是需要为新产品重新设计新软件,一来开发周期长,另一方面,代码要经过严格测试后才能推出,就会影响产品的面市时间。因此,将已有的、已经过测试的代码移植到新产品上就是一个很好的办法,进而开发者被要求
设计出可运行在不同硬件平台或不同操作系统下的应用程序。但是,由于系统设计可选择不同的设备、不同的子系统以及cpu,范围非常广泛,这样的不确定性势必会增加开发多平台软件的难度。
使用抽象层设计可移植代码
抽象层的先进之处在于它能够提取应用程序的基本内容,并将其与系统实现相隔离。这里关键是要将应用程序的逻辑算法与其运行环境相隔离。例如,在读取文件时,应用程序应该只关心文件的内容,而不在意文件是存在于fat文件系统中,还是ext2文件系统中;在数据通信中,通信双方应该只关心收发的数据本身,至于数据传输的媒体则不是应用程序该考虑的。
多平台软件的系统构成如图1所示,这种方法可广泛地应用在各种应用程序中。就像系统的机械组件可以被抽象,通信接口、cpu资源、存储设备等也可以被抽象。灵活使用抽象层可以将应用程序简化为一个紧凑并可重复利用的代码。
操作系统函数永远不要被直接调用,应将其包装到一个“操作系统抽象层”的库中,把应用程序从底层的操作系统中脱离出来。于是,当将应用程序移植到其他操作系统时,只要简单地移植操作系统抽象层即可,无需修改应用程序的代码。 这不仅将原应用程序的正确性和可靠性带到了新平台上,还加速了移植过程。此外,当在向新平台移植的过程中发现错误时,操作系统抽象层将是调试的最有效的起点。
操作系统抽象层应该输出函数原型,同时,不管底层的操作系统是如何实现的,抽象层应该对应用程序隐藏它们的一些特殊行为。例如,拿对信号量的操作来说,在大多数操作系统中,相同的进程可以多次获取一个信号量,而某些操作系统在递归获取信号量时会阻塞调用者。这里假设操作系统抽象层库输出一个信号量获取函数os_semtake(),那么它必须禁止该系统的标准操作,完成通用信号量获取的功能,使该函数独立于底层的操作系统。在递归获取信号量这个例子中,开发者必须实现递归行为本身。具体实现中,一些操作系统可能要比较两个任务的id,这两个任务一个是上次要求获取信号量的任务,另一个是本次要求获取信号量的任务。如果两个id相同,说明是在同一进程中,函数将增加信号量的计数器,且不调用操作系统的信号量获取函数。相应的,信号量释放函数必须对信号量的计数器进行递减操作,直到计数器为0,才调用操作系统程序中编写的函数封装应该保证在所有的操作系统中具有相同的行为,这可以避免底层操作系统的特殊性对应用程序的影响。
socket库函数中的select()提供了一个很好的例子来说明函数封装的重要性。对于不同的操作系统来说,可选择的设备有相当大的差异,一些系统只允许选择插口,而其它系统可以选择插口、管道和消息队列。在移植过程中,对底层操作系统实现的抽象使应用程序免于不必要的、杂乱的修改。如果某个操作系统没有实现select()的超时功能,只要在抽象层库中就能够完成修改。否则,就需要对应用程序的结构进行重大修改。
逻辑接口
这一步需要将物理接口转换为逻辑接口。比如一个系统中所有的外围设备都连接到一个总线上,那么就可以建立一组访问总线的函数,例如读总线数据函数busreadfrom()、向总线发送数据函数bussendto()等,这可以有效地将
总线操作从应用程序中提取出来。这样,无论总线是用pci、vme、串口或其它形式实现,都可使用逻辑接口将应用程序与物理接口隔离开。
逻辑接口特
在当今的软件设计中,为了在不同的产品线上重复使用相同的代码,需要将代码从一个平台移植到另一个平台。虽然这种代码的重复利用非常重要,但是很少有人讨论该采用何种方法来减少设计可移植软件的成本,本文将介绍一种可行的设计方案。
可移植代码的重要性
随着技术的发展,市场竞争的激烈,厂家必须不断开发新产品。如果是需要为新产品重新设计新软件,一来开发周期长,另一方面,代码要经过严格测试后才能推出,就会影响产品的面市时间。因此,将已有的、已经过测试的代码移植到新产品上就是一个很好的办法,进而开发者被要求
使用抽象层设计可移植代码
抽象层的先进之处在于它能够提取应用程序的基本内容,并将其与系统实现相隔离。这里关键是要将应用程序的逻辑算法与其运行环境相隔离。例如,在读取文件时,应用程序应该只关心文件的内容,而不在意文件是存在于fat文件系统中,还是ext2文件系统中;在数据通信中,通信双方应该只关心收发的数据本身,至于数据传输的媒体则不是应用程序该考虑的。
多平台软件的系统构成如图1所示,这种方法可广泛地应用在各种应用程序中。就像系统的机械组件可以被抽象,通信接口、cpu资源、存储设备等也可以被抽象。灵活使用抽象层可以将应用程序简化为一个紧凑并可重复利用的代码。
图1 多平台软件系统构成图
操作系统抽象层
操作系统抽象层应该输出函数原型,同时,不管底层的操作系统是如何实现的,抽象层应该对应用程序隐藏它们的一些特殊行为。例如,拿对信号量的操作来说,在大多数操作系统中,相同的进程可以多次获取一个信号量,而某些操作系统在递归获取信号量时会阻塞调用者。这里假设操作系统抽象层库输出一个信号量获取函数os_semtake(),那么它必须禁止该系统的标准操作,完成通用信号量获取的功能,使该函数独立于底层的操作系统。在递归获取信号量这个例子中,开发者必须实现递归行为本身。具体实现中,一些操作系统可能要比较两个任务的id,这两个任务一个是上次要求获取信号量的任务,另一个是本次要求获取信号量的任务。如果两个id相同,说明是在同一进程中,函数将增加信号量的计数器,且不调用操作系统的信号量获取函数。相应的,信号量释放函数必须对信号量的计数器进行递减操作,直到计数器为0,才调用操作系统程序中编写的函数封装应该保证在所有的操作系统中具有相同的行为,这可以避免底层操作系统的特殊性对应用程序的影响。
socket库函数中的select()提供了一个很好的例子来说明函数封装的重要性。对于不同的操作系统来说,可选择的设备有相当大的差异,一些系统只允许选择插口,而其它系统可以选择插口、管道和消息队列。在移植过程中,对底层操作系统实现的抽象使应用程序免于不必要的、杂乱的修改。如果某个操作系统没有实现select()的超时功能,只要在抽象层库中就能够完成修改。否则,就需要对应用程序的结构进行重大修改。
逻辑接口
这一步需要将物理接口转换为逻辑接口。比如一个系统中所有的外围设备都连接到一个总线上,那么就可以建立一组访问总线的函数,例如读总线数据函数busreadfrom()、向总线发送数据函数bussendto()等,这可以有效地将
逻辑接口特
上一篇:抢答器电路的改进
上一篇:手写输入防止密码被盗