作者:Vladimir Polin
近來,我們發布了“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 functionsprivate 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-engineLOCAL_SRC_FILES := jni-engine.cpp LOCAL_CFLAGS += -DTBB_USE_GCC_BUILTINS -std=c++11 -I$(TBB_PATH)/includeLOCAL_LDLIBS := -ltbb -L./ -L$(TBB_PATH)/<path_to_libtbb_so>include $(BUILD_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := libtbbLOCAL_SRC_FILES := libtbb.soinclude $(PREBUILT_SHARED_LIBRARY)
Application.mk
APP_ABI := x86APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rttiAPP_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。
*其他的名稱和品牌可能是其他所有者的資產。