質問

Cocoaの 'performSelectorOnMainThread:'メソッドの低レベルの実装の詳細について、誰かが知っている、または議論する適切なドキュメントへのポインターがあるかどうか疑問に思っていました。

私の推測では、おそらくかなり近いと思われますが、マッハポートまたはその上の抽象化を使用してスレッド内通信を提供し、マッハメッセージの一部としてセレクタ情報を渡します。

そうですか?違う?ありがとう!

更新09:39 AMPST

回答についてはEvan DiBiaseとMeckiに感謝しますが、明確にするために:実行ループで何が起こるか理解していますが、私が答えを探しているのは、 " where メソッドはキューに入れられますか?セレクター情報はどのようにキューに渡されますか?" Appleのドキュメント情報以上のものを探しています:私はそれらを読みました

更新14:21PST

Chris Hansonがコメントで良い点を挙げています。ここでの私の目的は、私自身のコードでそれらを利用するために基礎となるメカニズムを学ぶことではありません。むしろ、コードを実行するために別のスレッドにシグナルを送るプロセスの概念的な理解を深めたいだけです。私が言ったように、私自身の研究は、IPCのマッハメッセージングを利用してスレッド間でセレクター情報を渡すことを信じるように導きますが、私は具体的に何が起こっているかに関する具体的な情報を探しているので、物事を正しく理解していると確信できます。ありがとう!

2009年3月6日更新

この質問に対する回答を本当に見たいので、この質問に報奨金を用意しましたが、収集しようとしている場合は、現在提示されているすべての回答を含むすべてを必ず読んでください。これらの回答と私の最初の質問の両方へのコメントと、私が上に投稿した更新テキスト。 performSelectorOnMainThread:などで使用されるメカニズムの最低レベルの詳細を探しています。前述したように、Machと関係があると思われますポートが、私は本当に確かに知りたいです。与えられた答えが正しいことを確認できない限り、賞金は授与されません。みんなありがとう!

役に立ちましたか?

解決

はい、Machポートを使用します。これはどうなります:

  1. パフォーマンス情報(ターゲットオブジェクト、セレクタ、セレクタへのオプションのオブジェクト引数など)をカプセル化するデータブロックは、スレッドの実行ループ情報にキューイングされます。これは、最終的に pthread_mutex_lock を使用する @synchronized を使用して行われます。
  2. CFRunLoopSourceSignalが呼び出されて、ソースが起動する準備ができていることを通知します。
  3. CFRunLoopWakeUpが呼び出されて、メインスレッドの実行ループにウェイクアップの時間を知らせます。これは、mach_msgを使用して行われます。

Appleドキュメントから:

  

バージョン1のソースは、実行ループとカーネルによって管理されます。これらのソースは、Machポートを使用して、ソースの起動準備ができたことを通知します。メッセージがソースのMachポートに到着すると、ソースはカーネルによって自動的に通知されます。メッセージの内容は、ソースが起動されたときに処理するためにソースに提供されます。 CFMachPortおよびCFMessagePortの実行ループソースは、現在バージョン1ソースとして実装されています。

現在、スタックトレースを見ていますが、これが示すものです:

0 mach_msg
1 CFRunLoopWakeUp
2 -[NSThread _nq:]
3 -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:]
4 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:]

mach_msgにブレークポイントを設定すると、確認できるようになります。

他のヒント

もう1つの編集:

コメントの質問に答えるには:

  

IPCメカニズムの使用目的   スレッド間で情報を渡す?共有   記憶?ソケット?マッハメッセージング?

NSThreadはメインスレッドへの参照を内部に保存し、その参照を介してそのスレッドのNSRunloopへの参照を取得できます。 NSRunloopは内部的にリンクリストであり、NSTimerオブジェクトをrunloopに追加することにより、新しいリンクリスト要素が作成され、リストに追加されます。したがって、共有メモリであると言うことができます。実際にメインスレッドに属するリンクリストは、別のスレッド内から変更されるだけです。リンクリストの編集がスレッドセーフであることを確認するミューテックス/ロック(おそらくNSLockオブジェクト)があります。

擬似コード:

// Main Thread

for (;;) {
    lock(runloop->runloopLock);
    task = NULL;
    do {
        task = getNextTask(runloop);
        if (!task) {
            // function below unlocks the lock and
            // atomically sends thread to sleep.
            // If thread is woken up again, it will
            // get the lock again before continuing
            // running. See "man pthread_cond_wait"
            // as an example function that works
            // this way
            wait_for_notification(runloop->newTasks, runloop->runloopLock);
        }
    } while (!task);
    unlock(runloop->runloopLock);
    processTask(task);
}


// Other thread, perform selector on main thread
// selector is char *, containing the selector
// object is void *, reference to object

timer = createTimerInPast(selector, object);
runloop = getRunloopOfMainThread();
lock(runloop->runloopLock);
addTask(runloop, timer);
wake_all_sleeping(runloop->newTasks);
unlock(runloop->runloopLock);

もちろんこれは単純化されすぎており、ほとんどの詳細はここで関数間で隠されています。例えば。 getNextTaskは、タイマーが既に起動している場合にのみタイマーを返します。すべてのタイマーの起動日がまだ未来であり、処理する他のイベント(キーボード、UIからのマウスイベント、送信された通知など)がない場合、NULLを返します。


質問が何であるかまだわかりません。 セレクタは、呼び出されるメソッドの名前を含むC文字列にすぎません。すべてのメソッドは通常のC関数であり、メソッド名を文字列および関数ポインターとして含む文字列テーブルが存在します。これが、Objective-Cの実際の動作の基本です。

以下に書いたように、NSTimerオブジェクトが作成され、ターゲットオブジェクトへのポインタとメソッド名を含むC文字列へのポインタを取得し、タイマーが起動すると、文字列を使用して呼び出す適切なCメソッドを見つけますターゲットオブジェクトのテーブル(メソッドの文字列名が必要)(参照が必要)。

実装そのものではありませんが、かなり近いです:

CocoaのすべてのスレッドにはNSRunLoopがあります(常に存在します。スレッド用に作成する必要はありません)。 PerformSelectorOnMainThreadは、 this 、一度だけ発火し、発火時刻がすでに過去にある場合(したがって、すぐに発砲する必要がある)、次に、メインスレッドのNSRunLoopを取得し、そこにタイマーオブジェクトを追加します。メインスレッドが idle になるとすぐに、Runloopで処理する次のイベントを検索します(または、処理するものがなければスリープ状態になり、イベントが追加されるとすぐにウェイクアップします) )実行します。呼び出しをスケジュールするときにメインスレッドがビジーです。その場合、現在のタスクが完了するとすぐにタイマーイベントを処理するか、その時点でスリープ状態になります。その場合、イベントを追加することで起動します。すぐに処理します。

GNUStepは、Appleがどのようにそれを行っているかを調べるのに最適なソースです(ほとんどの場合、(すべてのクローズドソースのように、誰も確かに言うことはできません)。 GCCはObjective-Cを処理できるため(Appleだけが出荷する拡張機能ではなく、標準のGCCも処理できます)、Obj-CにAppleが出荷するすべての基本クラスがなくても役に立たないため、GNUコミュニティは-Macで使用する最も一般的なObj-Cクラスを実装します。その実装はOpenSourceです。

ここの最新ソースをダウンロードできますパッケージ。

それを展開し、詳細についてはNSThread、NSObjectおよびNSTimerの実装をご覧ください。 Appleはそれをそれほど大きくはしていないと思います。おそらくgdbを使用してそれを証明できますが、なぜ彼らはそのアプローチとは大きく異なるのでしょうか?それは賢い承認者です

NSObjectの performSelectorOnMainThread:withObject:waitUntilDone:メソッドのドキュメントのコメント:

  

このメソッドは、デフォルトの実行ループモード—つまり NSRunLoopCommonModes 定数。通常の実行ループ処理の一部として、メインスレッドはメッセージをデキューし(デフォルトの実行ループモードのいずれかで実行されていると仮定)、目的のメソッドを呼び出します。

Meckiが言ったように、 -performSelectorOn… の実装に使用できるより一般的なメカニズムは、 NSTimer です。

NSTimer は、 CFRunLoopTimer にブリッジされるフリーダイヤルです。 CFRunLoopTimer の実装– OS Xの通常のプロセスで実際に使用されるものとは限りませんが、CFLite(CoreFoundationのオープンソースサブセット; Darwin 9.4ソースコード(OS X  10.5.5に対応するCF-476.15はまだ利用できません。)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top