Android* チュートリアル: インテル® スレッディング・ビルディング・ブロック (インテル® TBB) を使用するマルチスレッド・アプリケーションの記述

同カテゴリーの次の記事

インテル® Atom™ プロセッサー・ベースのプラットフォームにおける Android* アプリケーションの開発と最適化

この記事は、インテル® デベロッパー・ゾーンに掲載されている「Android* Tutorial: Writing a Multithreaded Application using Intel® Threading Building Blocks.」の日本語参考訳です。


最近のブログ「Windows* 8 Tutorial: Writing a Multithreaded Application for the Windows Store* using Intel® Threading Building Blocks」 (英語) で、 並列計算エンジンはほかのモバイル・プラットフォームやデスクトップ・プラットフォームに簡単に移植できることを述べました。Android* はそのようなモバイル・プラットフォームの良い例です。

インテル® スレッディング・ビルディング・ブロック (インテル® TBB) の 安定リリース版では、試験的に Android* アプリケーションをサポートしています (つまり、JNI インターフェイスを介して Android* アプリケーションで使用するインテル® TBB ライブラリーをビルドできます)。このリリースは、threadingbuildingblocks.org (英語) からダウンロードできます。 

Linux* ホスト上でこの処理を行うには、インテル® TBB のソースを unpack し、< unpacked_dir >/build/android_setup.csh スクリプトを source して、ライブラリーをビルドします。開発リリースはソース形式でのみ配布されるため、事前にライブラリーをビルドする必要があります。Linux* 上で環境を設定し、ライブラリーをビルドする手順は、<unpacked_dir>/build/index.android.html ファイルに示されています。

GNU* make 3.81 が %PATH% (Microsoft* Windows* ホスト・プラットフォーム上) および $PATH (Linux* ホスト上) に設定されている場合、NDK 環境で次のコマンドを実行します。

$ gmake tbb tbbmalloc target=android

これで、インテル® TBB ライブラリーのビルドに必要な準備は整いました。次に Eclipse* からビルドする例を見てみましょう。この例では、Windows* 上で Android* SDK Tools Rev.21 と Android NDK Rev 8C を使用して、クロスプラットフォーム開発を行う際の手順を示します。

デフォルトのテンプレート [New Android Application] を使用して新しいプロジェクトを作成します。ここでは分かりやすいように、以前のポストと同じ “app1” という名前を付けます。

[Activity] [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 関数
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” ライブラリーについてはここで詳しい説明はいらないでしょう。TBB の C++ 言語機能をサポートするには gnustl_shared ライブラリーが必要です。    “jni-engine” ライブラリーについて以下に説明します。

“jni-engine” は計算エンジンを実装し、onClickSRCall() および onClickSRCall() という名前の JNI 用の C インターフェイスをエクスポートする С++ ライブラリーです。

NDK の開発ルールでは、ワークスペース内に “jni” フォルダーを作成し、そこに “jni-engine” ライブラリー用の 3 つのファイルを作成する必要があります。

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 := system

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.solibgnustl_shared.so、および libtbb.so を含むライブラリーが適切なフォルダーにコンパイルされます。

次に、Eclipse* に移動して、app1.apk ファイルをビルドします。これで AVD または実際のハードウェアでアプリケーションをインストールする準備が整いました。AVD 上でインストールすると、次のようになります。

これで、このアプリケーションが利用できます。このサンプル・アプリケーションは、Android* 向けのより複雑な並列アプリケーションを記述するベースとして使用できます。また、以前のブログのコードを使用してこの手順を行った場合は、アプリケーションを Android* に問題なく移植できるでしょう。

* その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

関連記事