利用英特尔® 移动平台软件开发套件,为应用注入移动环境感知能力

提交新文章

2008年01月25日 16:20



摘要
本文对移动平台软件开发套件进行了概括性说明,并列举了几个示例代码,以向您展示如何提升您应用的性能和连接感知能力。


简介

当前,笔记本电脑、超移动电脑(UMPC)、个人数字助理(PDA)以及智能电话等移动平台正迅速成为所有处于蓬勃发展阶段企业的 IT 基础设施的重要组成部分。这些移动平台的用户不仅需要在办公室运行其应用,而且还需在途中使用它们。这就为开发人员提出了一个挑战:即如何将现有应用扩展到多个平台,以满足这一移动计算环境中的用户需求。

英特尔® 移动平台软件开发套件(英特尔® 移动平台 SDK)可帮助简化针对移动环境的应用改造工作。它提供了一整套跨多平台和运行时环境的通用库、运行时组件和编程接口,能够帮助开发人员迅速高效地开发具有移动特性的应用,同时最大限度提高代码的重复使用率。在 SDK 的 v1.2 开放源版本中,平台支持范围和信息模型均有进一步的提高和扩展。


开发移动应用所面临的挑战

移动设备的用户正在日趋成熟和理性。他们不再满足那些只能在有限环境中运行有限时间的设备,而是提出了更高的要求:

  • 脱机工作——当断开网络时,用户仍然能够访问本地存储的数据并继续工作;当其与网络再次连接时,能够在设备与服务器之间再次实现数据同步。
  • 透明化连接管理——用户能够集中处理他们的核心任务,而无需管理与一个或多个网络的连接。
  • 功耗与性能的有效平衡——用户可在其设备的可用电池使用时间内获得最佳性能。

在开发新型移动应用或扩展现有移动应用方面,开发人员面临着两项艰巨挑战:

  • 创建能够感知平台环境和资源,并可有效适应变化的应用是一项新的范例,但现有软件解决方案并不能为其提供良好的支持。
  • 开发跨平台、跨运行时的解决方案,以便在多台客户机上部署应用极具挑战性,因为目前尚无标准方式来在多种设备上实施这一功能。

当应用能够感知其平台环境时,便可实现众多新的特性,从而支持其响应由于用户偏好所产生的环境变化。例如,在笔记本电脑系统上,用户可以选择某个选项,以指定笔记本电脑与外部电源相连时,病毒扫描应用设置为性能优化型,而笔记本电脑以电池供电时,则设置为节电模式。当笔记本电脑与外部电源断开时,病毒扫描程序会暂停后台执行,从而节省电池电量。当电源再次连接时,则重新开始病毒扫描。类似举例同样适用于网络连接状态、网络带宽、显示器分辨率、可用磁盘空间、可用内存、计算能力以及整体平台状态(如挂起模式和休眠模式)的改变情形。

应用的移动化,即让应用具备环境感知能力,是一项非常棘手的任务,它需要进行大量的编码和测试工作。在理想情况下,全新移动特性的开发应确保一套代码在多款平台上都能够使用。通过使用在不同编程语言中具有一致对象模型、命名规则和参数的通用编程接口,开发人员能够将不同平台间的代码差异降至最低。英特尔® 移动平台 SDK 中即采用了这种接口,它无需重新进行大量编码,即可在不同平台上对应用进行本地部署。


英特尔® 移动平台 SDK 概述

英特尔® 移动平台 SDK 可为您提供解决上述所有挑战所需的技术,让您的应用出色感知移动环境。尤为重要的是,SDK 中的许多特性还可帮助开发能够运行于不同运行时环境和平台的移动应用。

SDK 的另一项重要特性便是能够使应用感知并适应平台环境及资源的改变,从而做出有效调整,以充分利用平台的各项功能。SDK 中的运行时组件可监控并通知环境的改变,从而使应用能够实时对这些改变做出程式化的响应。该特性还可支持独立软件开发商(ISV)及用户,指定并控制移动平台对环境改变的响应方式。

英特尔® 移动平台 SDK 包含一个信息编程模型、开发库、可再分发运行时组件、《程序员指南》、大量代码样本以及测试实用程序。由于它是一个开发源项目,因此所有源代码全部可用。该 SDK 可支持三种编程接口:

  • 面向本地应用的 C++ 接口
  • Sun Microsystems Java*
  • Microsoft .NET* CLR

英特尔® 移动平台 SDK 的编程接口和信息模型在所有支持的语言和平台中都是一致的。该编程模型包括:

  • Class(类)、instance(实例)、property(属性)、method(方法)——这一组类表示系统设备和功能,称为“背景信息(context information)”,这是 v1.2 版本中的一处修订。这些类的实例主要利用属性和方法来描述并控制平台上的设备。
  • Event(事件)和 threshold notification(阈值通知)——当系统状态发生改变时,事件将通知应用。例如,应用可进行“注册”,从而在系统以电池供电时得到通知。当发生该事件时,运行时环境会执行回叫例程(callback routine)来通知应用,而应用可在此实时响应。例如,可对应用进行设置,从而在系统以电池供电时进入节能模式,以节省电量。此外,事件通知还可以与临界条件相绑定,如将应用设定为在电池电量不足 50% 时发出通知。
  • Collection(收集)和 enumeration(列举)——这些类可辅助发现系统上的设备,并列举设备中存在的多个实例。

在介绍示例代码前,先让我们来了解一下 SDK 的特性。


英特尔® 移动平台 SDK 提供的各项特性

以下几个示例介绍了英特尔® 移动平台 SDK 的一些设备和功能,并显示了如何利用这些它们来修改应用的行为,以优化系统的电源使用。该 SDK 提供了一系列设备和功能,可用于解决移动用户所面临的各种问题。先让我们了解一下 SDK 所支持的设备、背景和运行时:

设备

SDK 的设备对象模型可支持应用确定设备的状态。SDK v1.2 版支持如下设备:

  • Battery(电池)——用于获取系统电池的相关信息,如电量百分比、剩余使用时间以及制造商的序列号。
  • DisplayAdapter(显示适配器)——用于获取显示适配器的相关信息,包括制造商信息、色彩深度、分辨率以及刷新率。
  • LinkProtocol(链路协议)——用于说明系统上运行的链路协议(如 IEEE 802.3、802.11abg*),并监控网络连接的状态。LinkProtocol(链路协议)是与 NetworkAdapter(网卡)设备相关的逻辑设备。
  • NetworkAdapter(网卡)——用于描述系统中当前可用的网络适配器,如 802.3(以太网)、802.11(WiFi)以及蓝牙个人局域网(Bluetooth PAN*)、GPRS/CDMA(WWAN)等。
  • LogicalDisk(逻辑磁盘)——用于获取系统上本地及远程逻辑磁盘的相关信息,包括逻辑磁盘的格式和位置,以及总容量和剩余的存储空间。
  • Memory(内存)——用于获取系统上用于应用执行的 RAM 相关信息。
  • PhysicalDisk(物理磁盘)——用于获取系统附属物理磁盘的相关信息,包括制造商和型号,以及磁盘大小等信息。
  • Platform(平台)——用于获取系统平台的相关信息,包括系统进入挂起模式、休眠模式或关机等状态。
  • Processor(处理器)——用于获取系统微处理器的相关信息,如制造商、当前处理器频率以及处理器是支持英特尔® SIMD 流指令扩展 2(SSE2)还是英特尔® SIMD 流指令扩展 3(SSE3)。此外,该设备还能通过提供每个内核以及逻辑处理器的相关信息,来支持使用多核以及超线程(HT)技术的处理器。
  • RFID reader(RFID 阅读器)——用于支持系统读取来自 RFID 标签和写入 RFID 标签的数据。该性能具有多种使用方式,如验证系统用户、识别进行医疗的患者、库存控制,以及当标签处于固定点时的位置检测。

背景

背景层可提供系统上所有设备的综合信息。例如,如果系统具有两块电池,那么可使用 Power(电源)背景来确定两块电池的平均剩余电量。如果一块电池的剩余电量为 90%,而另一块电池为 100%,那么 Power(电源)背景将报告整体电量为 95%。SDK v1.2 版支持如下背景对象:

  • Bandwidth(带宽)——用于监控系统的网络带宽、应用进程以及网络会话。
  • Connectivity(连接)——用于获取系统的连接信息,如系统是否至少具有一个有效的网络接口与网络相连,或是否具有一个远程主机可访问。当系统失去网络连接,以及系统重新与网络进行连接时,该背景对象同样能通过事件来通知应用。
  • Display(显示)——可用于通过整合 DisplayAdapter(显示适配器)信息,来提供有关系统整体显示的信息,包括色彩深度,以及水平和垂直分辨率。
  • Power(电源)——用于获取系统电源信息,如系统电源供应方式(电池或外部交流电)以及系统整体电池电量。
  • Storage(存储)——用于提供持久存储(persistent storage)空间的信息,即系统的磁盘空间和内存。同时,当安装软件或在指定位置创建数据库时,还可确定给定文件夹的可用空间。

支持的运行时环境

以下操作系统可支持英特尔® 移动平台 SDK v1.2:

  • Microsoft Windows* XP Professional
  • Microsoft Windows* Vista Business/Ultimate Edition
  • Microsoft Windows* Tablet PC Edition 2005
  • Microsoft Windows* Mobile Edition 2003 for Pocket PC Platforms
  • Microsoft Windows* Mobile Edition 2003 for Smartphone Platforms
  • Microsoft Windows* Mobile Edition 5.0 for Pocket PC Platforms
  • Microsoft Windows* Mobile Edition 5.0 for Smartphone Platforms

除了上述可支持的现有操作系统版本外,我们还考虑加入 SDK 的 Linux 版。 

除了 Microsoft Windows Mobile Edition 2003 和 Mobile Edition 5.0 for Smartphone 仅支持 C++ 和 .NET 以外,所有运行时环境都支持面向 C++、Java 和 .NET 的编程接口。

英特尔® 移动平台软件开发套件 v1.2 包括如下目录和文件:

  • 文件(Docs)——包括《程序员指南》、版本说明和《快速启动指南》。
  • 项目——含有包括解决方案和项目文件在内的开发环境。就后向兼容性而言,它还包含一些程序库,可与采用 SDK 1.1 版开发、并与 SDK 1.1 版相连的应用实现连接。
  • 工具——包含一些可用于不同平台的工具:
    • 信息查看工具——两个样本应用(一个使用 Java 编写,另一个使用 C# 编写),具有以下 SDK 特性:
      • 列举系统中的设备,并查看其属性。
      • 进行注册,并在事件发生时接收及查看通知。

        您可将信息测试工具用作验证工具,以便将其结果同您调用英特尔® 移动平台 API 的实施返回结果进行比较。
    • 英特尔® 移动带宽图形用户界面(Intel® Mobile Bandwidth GUI)——该工具提供了一个图形用户界面,可用于查看单个系统的网络带宽使用情况并对其进行管理。用户可通过该界面获得在线帮助。
  • Bin——包含英特尔® 移动平台 SDK 运行时库和设置脚本。
  • Src——包含框架、提供商和绑定等的源文件。
  • 样本——包含展示如何利用 API 进行编程的样本代码


应用示例

本节包括的几个示例,用于演示如何使用英特尔® 移动平台 SDK 来检测系统电源及连接状态,同时还介绍了如何在多核系统上对工作负载进行多线程处理。如果您希望获得相关的样本代码,请查看上文 SDK 的样本目录,其中包含了使用 C++、Java* 和 C# 编写的示例。

例 1——电源感知

如果一个应用并非设计用于移动环境,那么它在移动环境中的表现可能就不能满足用户的需求。例如,当系统靠电池运行时,这种应用可能就会消耗过多的电量,从而缩短系统在两次充电之间所能运行的时间。此外,当电池电量较低时,该应用还可能会试图进行长时间运行(如烧录 CD 或 DVD)或高耗电操作。下面的应用示例显示了当系统由电池供电运行时,您可以如何利用英特尔® 移动平台 SDK 暂停一些非关键进程,以优化应用的电源使用。

 

问题陈述:应用未就节省系统电量而进行优化。您希望应用能够在系统依靠电池供电时,停止处理一些非关键功能;当系统重新利用外部交流电源供电时,重新处理这些功能。出于效率方面的考虑,您希望在不向操作系统询问电源连接状态的情况下,即可添加此项功能。

利用 SDK 解决该问题

英特尔® 移动平台 SDK 中的电源背景能够提供有关系统电源的信息。在解决这个问题的过程中,会用到 Power(电源)背景的如下特性:

  • Source property(来源属性)——Source property(来源属性)的值分为 External(外部)和 Internal(内部)。
  • 事件(Events)——监控的两个电源事件为 InternallyPowered(内部供电)和 ExternallyPowered(外部供电)。

为了解决这个问题,您可将如下功能加入到您的应用中:

  1. 注册表明系统电源发生改变的事件。
  2. 当启动应用时,检查系统连接状态,以决定应用最初应进入低耗电模式还是高性能模式。
  3. 当接收到事件通知时做出适当的响应。
    • 对于 InternallyPowered 事件,暂停所有可选的非关键进程,如后台病毒扫描或自动文字处理器拼写检查。
    • 对于 ExternallyPowered 事件,重新开始处理被暂停的可选非关键进程。
  4. 当关闭应用时,解除事件注册,并释放分配的内存。

下一节我们将向您详细介绍如何利用 SDK API 来实施该解决方案。

方法

下面的流程详细介绍了如何在应用中添加代码,以优化系统电源的使用。

第 1 步:

  1. 在使用英特尔® 移动平台 SDK 的项目中,引用适当的头文件和 .lib 文件。
    • 将头文件目录加入到项目的 include path(包括路径)中。默认路径为:“$MPSDK\Projects\Win32\VS2003\Binding\C++\inc”。
    • 在源文件顶端添加:

#include <IntelMobileCPP.h>

#include <Context\ContextClassObject.h>

#include <Context\PowerInstanceObject.h>

 

using namespace Intel::Mobile::Base;

using namespace Intel::Mobile::Context;

    • 将 lib 文件目录加入项目 lib 路径。默认路径为:“$MPSDK\Projects\Win32\VS2003\Binding\C++\lib”。
    • o 将下列代码添加至链接器输入:

IntelMobileCPP12.lib
ContextCPP12.lib

第 2 步:

  1. 添加一个在启动应用时运行的初始化例程,其中包含以下函数:
    • 创建指向 PowerInstance 对象的指针,并对其进行初始化。PowerInstance 对象将贯穿整个进程周期,以获取信息,并接收与电源相关的事件通知。

PowerInstance* pMyPowerInstance;

 

ContextClass MyClass;

pMyPowerInstance = dynamic_cast<PowerInstance*>

( MyClass.GetInstance(L"Power") );

  • 获取描述系统电源当前状态的值,如当前正在使用的电源(电池或外部交流电源),以及系统电池剩余电量的百分比。

    以下代码中的 IsNull() 方法能够确保某项特性在运行平台中得以支持。

unsigned int PowerInfo::GetPowerLevel()
	    {
              try
              {
                if (pMyPowerInstance != NULL)
                {
                  if (!pMyPowerInstance->PercentRemaining.IsNull())
                  {
                    unsigned __int32 value = pMyPowerInstance->
            PercentRemaining.GetValue();
                    return value;
                  }
                }
              }
              catch (IntelMobileException& ex)
              {
                //Handle Exception here.
                ASSERT(0);
              }
             
              return 0;
            }
             
            CString PowerInfo::GetPowerSource()
            {
              CString rv = _T("Unknown");
             
              try
              {
                if (pMyPowerInstance != NULL)
                {
                  if (!pMyPowerInstance->Source.IsNull())
                  {
                    SourceEnum value = pMyPowerInstance->Source.GetValue();
                    rv = value.ToString();      }
                }
              }
              catch (IntelMobileException& ex)
              {
                //Handle Exception here.
                ASSERT(0);
              }
             
              return rv;
            }
            
  • 定义一个称为 PowerObserver 的观察者(Observer)类。系统将注册该类的一个实例来处理事件。(请参见第 3 步,了解如何实施该类。)

#include <Base\base_Event.h>

#include <Base\base_Observer.h>

using namespace Intel::Mobile::Base;

 

class PowerObserver : public Observer

{

  public:

    void Notify( const Event& event);

    void SetDialogPtr(CDialog *DialogPtr); 

  private:

    CDialog *MyUIDialog;  //Used to update the user interface

};

  • 注册 PowerObserver 类的一个称为 MyPowerObserver 的实例,以获取与电源相关的事件通知。在下面的示例代码中,MyPowerObserver 注册为监视 ExternalPower、InternalPower、以及 StatusChange 事件。

void PowerInfo::RegisterObserver()

{

assert(pMyPowerInstance != NULL);

pMyPowerInstance->ExternallyPowered.AddObserver(MyPowerObserver);

pMyPowerInstance->InternallyPowered.AddObserver(MyPowerObserver);

pMyPowerInstance->StatusChanged.AddObserver(MyPowerObserver);

}

第 3 步:

  • 添加事件处理程序,以便接收系统中电源相关变化的通知。下面的代码样本主要涉及三类事件:交流电源(外部)变化、电池电源(内部)变化,以及电池电量的变化。本简化的示例中的响应是发送(post)WM_PAINT,从而引起主对话框的更新。

    事件处理程序对事件更为常见的响应,则是更改应用行为以优化电源使用,如:当系统进入电池电源模式时关闭后台处理;当与外部交流电电源重新连接时,再启动后台处理。

    由于通知方法在一条单独的线程上调用,因此,无论何时使用通知函数来更新共享数据,都必须在代码中实施临界区(critical section),以保护共享数据。下面的简单代码样本中并未使用临界区,但多数应用都需要。

#include "stdafx.h"

#include "PowerObserver.h"

#include <IntelMobileCPP.h>

 

using namespace Intel::Mobile::Base;

using namespace Intel::Mobile::Context;

 

void PowerObserver::Notify(const Event& event)

{

  try

  {

    switch (event.GetType())

    {

      case Event::eExternallyPowered:

        OutputDebugString(_T("ExternallyPowered Event received.\n"));

        MyUIDialog->PostMessage(WM_PAINT);  //Tell the main dialog to repaint.

        break;

 

      case Event::eInternallyPowered:

       OutputDebugString(_T("InternallyPowered Event received.\n"));

       MyUIDialog->PostMessage(WM_PAINT);  //Tell the main dialog to repaint.

        break;

 

      case Event::eStatusChange:

        OutputDebugString(_T("StatusChanged Event received.\n"));

        MyUIDialog->PostMessage(WM_PAINT);  //Tell the main dialog to repaint.

        break;

    }

  }

  catch (IntelMobileException& ex)

  {

   OutputDebugString(_T("IntelMobileException exception caught!!!\n"));

  }

}

第 4 步:

  • 添加一个清除例程,并在关机时运行,以取消电源相关事件的观察者注册并将其删除。

void PowerInfo::UnregisterObserver()

{

assert(pMyPowerInstance != NULL);

pMyPowerInstance->ExternallyPowered.RemoveObserver(MyPowerObserver);

pMyPowerInstance->InternallyPowered.RemoveObserver(MyPowerObserver);

pMyPowerInstance->StatusChanged.RemoveObserver(MyPowerObserver);

}


现在,该项目就可编译和运行了。在应用运行时,拔掉您笔记本电脑上的交流适配器,您便会看到电源状态从“External(外部)”改变到“Internal(内部)” 。将适配器重新插到笔记本电脑上,您又会看到状态变回“External”。如果一直不插回去,那么“Power Level(电源水平)”就会发生变化,因为数值每降低一次,就会发生 StatusChanged 事件,导致应用获得新值。现在,由于应用能够“了解”系统的电源状态,它便可在使用交流电源时启用众多附加特性,但在使用电池电源时又会适当去掉某些特性。


例 2——在多枚 CPU 内核间分配工作负载

并非专门设计用于多核系统的应用,在任何给定的时间内只能利用一个内核。随着多核 CPU 在移动系统以及台式机和服务器系统中的使用,用户可以获得的处理能力在成倍地增加。例如,单线程应用能够被重新设计为多线程应用,这样它就能够在多核系统上以多线程模式运行。这样做能够支持应用在更短的时间内完成更多的工作。下面的应用显示了利用英特尔® 移动平台 SDK,您如何可动态地创建线程并使之与系统中的内核数量相匹配。

问题陈述:一个单线程应用将进行多线程处理,以充分利用多核 CPU 的强大优势。此外,该应用还需能够动态地匹配系统中的内核数量,因为未来处理器的内核数量很可能还会增加。

利用 SDK 解决该问题

英特尔® 移动平台 SDK 中提供的 ProcessorClassProcessorCollection 以及 ProcessorInstance 对象能够获取有关系统处理器的信息。在解决该问题的过程中,将用到这些对象的以下特性:

  • ProcessorClass GetInstances() 方法——返回系统中处理器信息汇总。
  • ProcessorCollection HasNext()Next() 方法——通过对象集来提供一种列举方式。
  • ProcessorInstance 属性——提供各处理器的内核数目。

为了解决该问题,您需要:

  1. 在应用启动时,创建一个 ProcessorClass 对象。
  2. 利用 ProcessorClass 对象获得一个 ProcessorCollection 对象。
  3. 利用 ProcessorCollection 对象来列举 ProcessorInstance 对象。
  4. 为每个 ProcessorInstance 对象调用 GetValue() 函数,以查看 CoreCount 属性。
  5. 基于获得的内核数目,将工作等量分配给每条线程。密切关注可能发生的线程同步问题。

下节将详细说明如何利用 SDK 组件来实施该解决方案。

方法

下面我们将详细描述如何将代码加入到 C++ 应用中,以优化系统中多核的使用。

第 1 步:

在需要使用英特尔® 移动平台 SDK 的项目中,引用适当的头文件和 .lib 文件。

  • 将头文件目录加入到项目的 include path(包括路径)中。默认路径为:“$MPSDK\Projects\Win32\VS2003\Binding\C++\inc”。
  • 在源文件顶端添加:

#include <IntelMobileCPP.h>

#include <Processor\ProcessorClassObject.h>

 

using namespace Intel::Mobile::Processor;

  • 将 lib 文件目录加入项目 lib 路径。默认路径为:“C:\Program Files\Intel\Intel(R) Mobile Platform SDK 1.1\Development\C++\lib”。
  • 将下列代码添加至链接器输入:

IntelMobileCPP12.lib

ProcessorCPP12.lib

第 2 步:

  • 添加一个例程,用于在应用启动时运行,以获得系统中内核的数量。如果该数值存储于一个可供应用其它部分访问的变量中,那么该例程只需运行一次。

unsigned GetCoreCount()

{

              unsigned CoreCount = 0;

              ProcessorCollection* pMyCollection = NULL;

              ProcessorInstance* pMyInstance = NULL;

 

              //Use try catch blocks to handle exceptions that could be thrown

              //  by the Intel® Mobile Platform Runtime.

              try

              {

                            //Get a collection of processors

                            ProcessorClass MyClass;

                            pMyCollection =

                                          dynamic_cast<ProcessorCollection*>(MyClass.GetInstances());

 

                            //Enumerate through the processors

                            while (pMyCollection->HasNext())

                            {

                                          pMyInstance =

                                                        dynamic_cast<ProcessorInstance*>(pMyCollection->Next());

 

                                          //Check and make sure there is data available

                                          if ( !pMyInstance->CoreCount.IsNull() )

                                          {

                                                        //Get the value.  Add to CoreCount should there

                                                        //   be more than one CPU

                                                        CoreCount += pMyInstance->CoreCount.GetValue();

                                          }

 

                                          delete pMyInstance;

                                          pMyInstance = NULL;

                            }

              }

              catch (IntelMobileException& ex)

              {

                            wprintf( L"\n------------ Exception Occurred ------------\n" );

                            wprintf( L"Message: %s\n", ex.GetGeneralMessage().GetValue() );

                            wprintf( L"Source: %s\n", ex.GetSource().GetValue() );

                            wprintf( L"Target Site: %s\n", ex.GetTargetSite().GetValue() );

                            wprintf( L"Error Code: %s\n", ex.GetErrorCode().GetValue() );

                            wprintf( L"Detailed Error Info: %s\n", ex.GetDetailErrorInfo().GetValue() );

              }

              catch ( ... )

              {

                            wprintf( L"\n------------ Exception Occurred ------------\n" );

              }

 

              //Clean up objects created earlier.

              if ( pMyInstance )

                            delete pMyInstance;

 

              if ( pMyCollection )

                            delete pMyCollection;

 

              return CoreCount;  //Return the final count of cores

}

第 3 步:

  • 现在,应用已经了解系统中内核的数量,接下来需要将工作负载分配为多个任务,以便每个线程的处理。不同应用将以不同的方式完成。在提供的样本应用中,ThreadWorkloads 阵列呈动态分配,并计算出每条线程所需处理的工作量以便平均分配。

//Determine a workload that is uniformly distributed between threads

int *ThreadWorkloads;

ThreadWorkloads = new int[CoreCount];

memset(ThreadWorkloads, 0, sizeof(int) * CoreCount);

for (int i=0; i < TotalNum; i++)

              ThreadWorkloads[i % CoreCount]++;

第 4 步:

  • 由于先前并不知道线程的数量,因此需要动态地创建专门针对线程的数据结构,如线程句柄和线程参数。

	    HANDLE *hThreads = new HANDLE[CoreCount];
	    memset(hThreads, 0, sizeof(HANDLE) * CoreCount);
            ThreadData_Struct *ThreadData = new ThreadData_Struct[CoreCount];
            memset(ThreadData, 0, sizeof(ThreadData_Struct) * CoreCount);

第 5 步:

  • 现在便可以编写代码来创建线程。每条线程获得其唯一的参数,指示其将要处理的工作负载。

int CurrentValue = StartNum;

for (unsigned i=0; i<CoreCount; i++)

{

              ThreadData[i].BeginValue = CurrentValue;

              ThreadData[i].EndValue = CurrentValue + ThreadWorkloads[i] - 1;

              hThreads[i] = CreateThread(              NULL, 0, ThreadFunc,

                                  &ThreadData[i], 0, &dwThreadId);

              if (hThreads[i] == NULL)

              {

                            printf( "CreateThread failed (%d)!\n", GetLastError() );

                            printf( "Processes Aborted.\n");

                            break;

              }

                            CurrentValue += ThreadWorkloads[i];

}

第 6 步:

  • 最后,主线程中断,并等待工作端线程完成指派给它们的任务。在样本应用中,应用将计算消耗的总计算时间,并等待线程结束后将其清除。

//Wait for all the threads to exit. 
WaitForMultipleObjects(CoreCount, hThreads, TRUE, INFINITE); 

//Clean up 
for (unsigned i=0; i<CoreCount; i++) 
              if (hThreads[i] != NULL) 
     CloseHandle(hThreads[i]); 
delete[] hThreads; 
delete[] ThreadData; 
delete[] ThreadWorkloads; 
printf("Elapsed time: %u msec\n", GetTickCount() - StartTime); 

现在,该项目将编译和运行。当应用运行时,您会先看到来自单线程实施的结果,然后是多线程实施的结果。如果运行于采用双核技术(如英特尔® 迅驰® 双核处理器技术)的系统之上,那么多线程实施结果的速度约为单线程的两倍。

例 3——处理网络中断

分布式应用的设计未考虑间歇性网络连接,这可能会为移动平台用户带来麻烦。例如,当系统意外断开网络时,对于等待与远程资源保持持续连接的应用而言,其最佳可能是发出错误消息,最坏可能是意外终止或整个系统处于不稳定状态。分布式应用能够在脱机模式下运行,但不能检测并适应网络状态的变化,它需要某种形式的用户介入才能返回联机模式,如应用重启或客户端-服务器端同步进程的手动启动。在真正的移动式应用中,软件可无缝处理网络中断和重新连接,无需用户介入,还可友好地通知用户状态的变化。

问题陈述: 当客户端与服务器断开连接时,并非针对移动性而专门设计的应用会发出奇怪的错误消息,并出现其它异常行为。客户端重新连接后,必须重新启动应用。而您希望应用能够无缝地处理网络中断和重新连接。

利用 SDK 解决该问题

英特尔® 移动平台 SDK 中提供的 ConnectivityInstance 对象作为背景信息层的一部分,可提取并整合系统中所有网络设备的信息。在解决该问题中,将用到该对象的以下特性:

  • IpAddressChanged 事件——系统 IP 地址表发生变化时随即发生的事件。
  • RouteTableChanged 事件——系统路由表发生变化时随即发生的事件。
  • IsReachable() 方法——该方法可支持调用者(caller)确定特定网络位置或服务是否可用。

方法

虽然本示例的样本应用并未提供,但是在 SDK 的 development 目录下提供了与 ConnectivityInstance 对象有关的样本代码。请查看样本代码中的以下项目:ConnectivitySampleDisconnectEventSampleConnectEventSample。您可依照以下步骤解决这个问题:

  1. 创建一个 ConnectivityInstance 对象的实例,并利用 IsReachable() 方法检查与网络资源连接的当前状态。如果资源可利用,则在“连接”模式中运行应用。如果资源不可利用,则在“脱机”模式中运行应用。
  2. 针对 IpAddressChanged 和/或 RouteTableChanged 事件进行注册。在启动时,应用将为事件注册一个观察者,这样就能够针对网络路由和 IP 地址表的变化对其进行通知。Connectivity 背景对象用于监视网络连接的状态。如果使用动态主机配置协议(Dynamic Host Configuration Protocol,DHCP),那么系统中的网络适配器会重新连接或断开,当指定 IP 地址时,则会触发IpAddressChange 事件。一旦网络连接发生变化时,就会触发 RouteTableChanged 事件,该事件可用作未使用 DHCP 时的网络状态变化指示器。
  3. 3 修改您的应用,以响应网络连接状态的变化。最重要的一点是确定网络状态的变化是否相关。例如,当用户连接至网络并通过 DHCP 服务器分配 IP 地址时,该网络可能不同于远程资源所属的网络。为了确定网络状态的变化是否相关,需要将到网络服务的路径作为参数,来调用一个 IsReachable() 方法。如果调用 IsReachable() 的返回结果为假,那么软件将根据之前的状态,转至或继续脱机模式(如,应使用本地数据高速缓存)。相反,如果调用 IsReachable() 的返回结果为真,那么应用将根据之前的状态,转至或继续在线模式(如,本地数据与远程数据存储实现同步)。
  4. 向应用添加特性,以便用户清楚地了解网络连接状态的变化。例如,应用会显示一则消息,如“网络已中断。您使用的数据已保存在本地。”或者,您可以在应用中加入状态栏图标,以便在应用脱机运行时进行显示。
  5. 向应用添加关闭程序,从而在应用关闭时解除面向RouteTableChangedIpAddressChanged 事件的观察者对象的注册。


结论

随着越来越多的用户开始选择使用移动平台,软件开发人员也需要修改其应用以应对资源和环境的变化。通过向应用中添加移动特性,用户将获得专为移动环境而优化的一致的应用行为。

正如本文所述,英特尔® 移动平台 SDK 不仅能够帮您将移动特性添加到应用中,同时还能缩短开发时间,最大限度地实现代码的重复利用。它可为您提供以下优势:

  • 多平台/多运行时的环境支持
  • 通用一致的编程接口,可支持访问移动应用所需的关键能力
  • 轻松实现应用对环境的感知能力


参考资料

如欲了解更多信息,请访问以下英特尔® 移动平台 SDK 开源项目: 



附录 A:英特尔® 移动平台 SDK v1.2 的全新特性

英特尔® 移动平台 SDK v1.2 版的整体改进主要是扩展了平台的支持范围,提高了信息的丰富度,同时还有其它方面的改进。以下是针对 v1.1 版本所实施的改进:

  • RFID/GPRS/CDMA 只具备捆绑接口,在 1.2 开源版本中不支持相应的提供商。
  • 支持其它开发环境,包括 Microsoft Visual Studio* 2005 和 .NET Framework 2.0。
  • 数据包中包含英特尔® 移动平台提供商开发套件,可协助您开发适合自己设备的插件模块。
  • 通过避免系统中同时存在多台移动服务器的情况,来实现性能提升
  • 支持与多种 C 运行时库连接,不仅包括动态可加载库(/MD 和 /MDd 编译器选项),还包括静态库(/MT 和 /MTd 编译器选项)。
  • 支持检测英特尔® 虚拟化技术。
  • 支持检测英特尔® 迅驰® 处理器技术。