The Thread Manager
出典: MDC
この記事は Firefox 3 の新機能について述べています
Firefox 3 で導入されたスレッドマネージャは、スレッドを作成して、処理を行うイベントをそのスレッドに割り当てる便利な方法を提供します。
目次 |
[編集] インタフェース
スレッドのサポートを提供するインタフェースは、以下のようにいくつか存在します。
nsIThreadManager- スレッドを作成できるようにするスレッドマネージャそのもの。
nsIThread- この
nsIThreadインタフェースは、オペレーティングシステムのスレッドをカプセル化したもので、コードからマルチスレッドに対する簡易なクロスプラットフォームアクセスを提供します。 nsIThreadPool- スレッドプールは、限られた一連のワーカースレッドを提供します。イベントをプールに割り当てる際、プールは、そのイベントを処理するために利用可能なワーカースレッドを選択する役割を果たします。
nsIThreadInternalnsIThreadのサブクラスで、XPCOM のスレッドオブジェクトによって実装されており、スレッドへのアクティビティ割り当て監視サポートを提供します。nsIThreadObserver- スレッドを監視する機能を提供します。スレッドにイベントが割り当てられた際や、それらのイベントの処理が完了した際に、通知を受け取ることができます。
nsIThreadEventFilter- このインタフェースは
nsIThreadInternal内のpushEventQueue()メソッドで使われており、イベントのフィルタリングを可能にします。
[編集] スレッドマネージャの使い方
スレッドマネージャを使用するには、各スレッドのワーキングコードを nsIRunnable XPCOM オブジェクトにカプセル化しなければなりません。このオブジェクトは全体を JavaScript で書くことができ、それほど難しくありません。
このセクションでは簡単な例を見ていきます。
[編集] バックグラウンドスレッド
まず、バックグラウンドスレッドで行われる処理を扱う XPCOM オブジェクトが必要になります。
var workingThread = function(threadID, number) {
this.threadID = threadID;
this.number = number;
this.result = 0;
};
workingThread.prototype = {
run: function() {
try {
// ここでワーキングスレッドが処理を行う
for (var i = 0; i<= this.number; i++) {
this.result += i;
}
// 処理が終了したら、終了を知らせるためにメインスレッドにコールバックする
main.dispatch(new mainThread(this.threadID, this.result),
background.DISPATCH_NORMAL);
} catch(err) {
Components.utils.reportError(err);
}
},
QueryInterface: function(iid) {
if (iid.equals(Components.interfaces.nsIRunnable) ||
iid.equals(Components.interfaces.nsISupports)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
このスレッドのコンストラクタでは、スレッドの ID と 数値をローカル変数に保存し、result 変数を 0 に設定しています。 これらの変数はスレッドの実行時に使用されます。
このオブジェクトにはコンストラクタのほかに 2 つのメソッドがあります:
run()run()メソッドはnsIThreadインタフェースのdispatch()メソッドが呼び出されたときに呼び出されます。これはバックグラウンドスレッドで実際の作業を行うルーチンです。 この例では、0 から this.number までのすべての数の合計を計算しています。 計算が終了すると、mainThreadオブジェクトを使ってメインスレッドにアクセスし、計算結果を共有するためにコールバックをメインスレッドにディスパッチします。QueryInterface()- スレッドの XPCOM オブジェクトは
nsIRunnableインタフェースを扱う必要があるため、オブジェクトがnsIRunnableインタフェースを扱っているかを尋ねるためにこのメソッドが呼び出されたときに、正しい反応を返さなければなりません。
[編集] メインスレッド
メインスレッドを扱う XPCOM オブジェクトはバックグラウンドタスクからのコールバックとして使用されます。このオブジェクトの run() メソッドは、バックグラウンドスレッドが計算結果をユーザーに知らせようとしたときに呼び出されます。バックグラウンドスレッドはユーザーインタフェースに触れることができず、メインスレッドに依頼しなければならないため、このオブジェクトが必要になります。
var mainThread = function(threadID, result) {
this.threadID = threadID;
this.result = result;
};
mainThread.prototype = {
run: function() {
try {
// ここでワーキングスレッドの完了に対して反応を返す
alert('Thread ' + this.threadID + ' finished with result: ' + this.result);
} catch(err) {
Components.utils.reportError(err);
}
},
QueryInterface: function(iid) {
if (iid.equals(Components.interfaces.nsIRunnable) ||
iid.equals(Components.interfaces.nsISupports)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
この例では run() メソッドは単純に警告ボックスを使ってユーザーに出力を表示します。
[編集] 仕上げ
実際にスレッドマネージャを使ってバックグラウンドでこれらの計算を行うには、まず workingThread のタスクを実行する nsIThread オブジェクトを作成する必要があります:
var background = Components.classes["@mozilla.org/thread-manager;1"].getService().newThread(0);
それに加えて、メインスレッドの nsIThread の参照を得る必要があります:
var main = Components.classes["@mozilla.org/thread-manager;1"].getService().mainThread;
この情報を得たら、タスクをバックグラウンドスレッドに割り当てることができます。
background.dispatch(new workingThread(1, 5000000), background.DISPATCH_NORMAL);
これによりバックグラウンドスレッドの実行が開始され、0 と 5,000,000 の間のすべての数の合計が計算されます。作業が終了すると、メインスレッドの run() メソッドが呼び出され、結果をユーザーと共有します。それまでの間、メインスレッドはユーザーの操作に反応するなどの自分の作業を続けることができます。