近来,我们发布了“Windows* 8 教程: 使用英特尔® 线程构建模块为 Windows 应用商店* 编写多线程应用”。 其中我们提到,并行计算引擎很容易导入其他移动或台式机平台。 Android 是这种移动平台的一个典型的例子。
在最新发布的英特尔® 线程构建模块(英特尔® TBB)的稳定版本中,我们为 Android 应用增加了实验支持,即构建英特尔® TBB 库,通过 JNI 界面在 Android 应用中使用。您可以从threadingbuildingblocks.org中下载 该版本。
如要在 Linux* 主机上启动流程,请打开英特尔 TBB 源发布,找到<unpacked_dir>/build/android_setup.csh 脚本 并构建库。您必须构建库,因为开发版本仅可在源形式下发布。 <unpacked_dir>/build/index.android.html 文件中包括在 Linux 上配置环境和构建库的说明。
假定 %PATH%(在 Microsoft Windows* 主机平台上)和 $PATH (在 Linux 平台上)中 gnu make 3.81 可用,我们需要在 NDK 环境中执行下列命令来为 Android 构建英特尔 TBB 库:gmake tbb tbbmalloc target=android
上述是构建库所需的操作;我们现在可以使用 Eclipse* 来构建示例。 对于下列的示例,我将使用 Windows* 的 Android SDK 工具 Rev.21 和 Android NDK Rev 8C 来说明跨平台开发的流程。
使用默认模板《New Android Application》创建新对象。 为简单起见,我们将其命名为“app1”,与上述的发布相同:
选择 FullscreenActivity 作为“活动”。 有关该模板的内容到此为止。 请注意不可以使用 com.example* 为 Google Play* 命名,但是它可以很好地帮助我们理解。
然后向主帧中添加几个按钮。 添加后,主帧的 XML 文件(app1/res/layout/activity_fullscreen.xml)如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#0099cc" tools:context=".FullscreenActivity" > <TextView android:id="@+id/fullscreen_content" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:keepScreenOn="true" android:text="@string/dummy_content" android:textColor="#33b5e5" android:textSize="50sp" android:textStyle="bold" /> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" > <LinearLayout android:id="@+id/fullscreen_content_controls" style="?buttonBarStyle" android:layout_width="match_parent" android:layout_height="74dp" android:layout_gravity="bottom|center_horizontal" android:background="@color/black_overlay" android:orientation="horizontal" tools:ignore="UselessParent" > <Button android:id="@+id/dummy_button1" style="?buttonBarButtonStyle" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/dummy_button1" android:onClick="onClickSR" /> <Button android:id="@+id/dummy_button2" style="?buttonBarButtonStyle" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/dummy_button2" android:onClick="onClickDR" /> </LinearLayout> </FrameLayout> </FrameLayout>
字符串文件(app1/res/values/strings.xml)如下
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Sample</string> <string name="dummy_content">Reduce sample</string> <string name="dummy_button1">Simple Reduce</string> <string name="dummy_button2">Deterministic Reduce</string> </resources>
然后添加按钮处理器:
// JNI functions private native float onClickDRCall(); private native float onClickSRCall(); public void onClickDR(View myView) { TextView tv=(TextView)(this.findViewById(R.id.fullscreen_content)); float res=onClickDRCall(); tv.setText("Result DR is n" + res); } public void onClickSR(View myView) { TextView tv=(TextView)(this.findViewById(R.id.fullscreen_content)); float res=onClickSRCall(); tv.setText("Result SR is n" + res); }
然后,将库加载至 FullscreenActivity.java 文件:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); … System.loadLibrary("gnustl_shared"); System.loadLibrary("tbb"); System.loadLibrary("jni-engine"); }
在使用 "tbb" 库时应清除所有内容,且需要使用 "gnustl_shared" 库来支持 TBB 的 C++ 语言特性。但是,对于 "jni-engine" 库,我们需要获得更多内容。
"jni-engine" 是 С++ 库,可执行计算引擎并为名为 onClickSRCall() 和 onClickSRCall() 的 JNI 调用输出 C 接口。
根据 NDK 开发规则,在工作区内创建文件夹 “jni” 并在该文件夹下专门针对 "jni-engine" 库创建 3 个文件。
这些文件是:
Android.mk ( <> 括号中的文本应使用实际的值替换)
LOCAL_PATH := $(call my-dir) TBB_PATH := <path_to_the_package> include $(CLEAR_VARS) LOCAL_MODULE := jni-engine LOCAL_SRC_FILES := jni-engine.cpp LOCAL_CFLAGS += -DTBB_USE_GCC_BUILTINS -std=c++11 -I$(TBB_PATH)/include LOCAL_LDLIBS := -ltbb -L./ -L$(TBB_PATH)/<path_to_libtbb_so> include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libtbb LOCAL_SRC_FILES := libtbb.so include $(PREBUILT_SHARED_LIBRARY)
Application.mk
APP_ABI := x86 APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti APP_STL := gnustl_shared
jni-engine.cpp:
#include <jni.h> #include "tbb/parallel_reduce.h" #include "tbb/blocked_range.h" float SR_Click() { int N=10000000; float fr = 1.0f/(float)N; float sum = tbb::parallel_reduce( tbb::blocked_range<int>(0,N), 0.0f, [=](const tbb::blocked_range<int>& r, float sum)->float { for( int i=r.begin(); i!=r.end(); ++i ) sum += fr; return sum; }, []( float x, float y )->float { return x+y; } ); return sum; } float DR_Click() { int N=10000000; float fr = 1.0f/(float)N; float sum = tbb::parallel_deterministic_reduce( tbb::blocked_range<int>(0,N), 0.0f, [=](const tbb::blocked_range<int>& r, float sum)->float { for( int i=r.begin(); i!=r.end(); ++i ) sum += fr; return sum; }, []( float x, float y )->float { return x+y; } ); return sum; } extern "C" JNIEXPORT jfloat JNICALL Java_com_example_app1_FullscreenActivity_onClickDRCall(JNIEnv *env, jobject obj) { return DR_Click(); } extern "C" JNIEXPORT jfloat JNICALL Java_com_example_app1_FullscreenActivity_onClickSRCall(JNIEnv *env, jobject obj) { return SR_Click(); }
我们使用了上一篇博客中的算法。
当我们使用 NDK 进行构建时,它将库编写至所需的文件夹,包括我们的 libjni-engine.so、libgnustl_shared.so 和 libtbb.so 库。
接下来,切换回 Eclipse 并构建 app1.apk 文件。 现在,可将应用安装至 AVD 或实际的硬件上。 在 AVD 上时,它应如下图所示
操作到此结束! 这一简单应用现可使用,且可以作为基础为 Android 编写更复杂的并行应用。 对于使用上一篇博客中的代码的用户, 应用已成功移植到 Android。
*其他的名称和品牌可能是其他所有者的资产。