1

マルチスレッドプログラミングとスレッドセーフについて調べ始めたばかりです。私はビジー待機に精通しており、少し調査した結果、スピンロックの背後にある理論に精通しているので、Mac での OSSpinLock の実装を調べてみようと思いました。次の関数に要約されます (objc-os.h で定義)。

static inline void ARRSpinLockLock(ARRSpinLock *l)
{
again:
   /* ... Busy-waiting ... */
    thread_switch(THREAD_NULL, SWITCH_OPTION_DEPRESS, 1);
    goto again;
}

(完全な実装はこちら)

thread_switch少し掘り下げた後、のパラメーターが何をするかについてのおおよそのアイデアが得られました(このサイトは私が見つけた場所です)。私が読んだことの私の解釈は、thread_switch へのこの特定の呼び出しが次に利用可能なスレッドに切り替わり、現在のスレッドの優先度を 1 サイクルの絶対最小値に下げるというものです。「最終的に」(CPU 時間で) このスレッドは再びアクティブになりgoto again;、ビジー待機を最初からやり直す命令をすぐに実行します。

私の質問ですが、なぜこの呼び出しが実際に必要なのですか? スピンロック (今回は Windows 用) の別の実装をここで見つけました、(Windows と同等の) スレッド切り替え呼び出しはまったく含まれていません。

4

2 に答える 2

3

スピン ロックはさまざまな方法で実装できます。Windows 用の別の実装が見つかった場合は、SpinLockそのための別のアルゴリズムが表示されます (またはが含まれる場合があります)。SetThreadPrioritySleepSwitchToThread

のデフォルトの実装ARRSpinLockLockは十分に賢く、最初の回転サイクルの後、しばらくの間スレッドの優先度を「低下」させます。これには次の利点があります。

  • ロックを所有するスレッドがロックを解放する機会が増えます。
  • orを実行する際のCPU 時間(および電力) の浪費が少なくなります。NOPPAUSE

Windows API はその機会を提供しないため、Windows の実装はそれを行いません (同等のthread_switch()関数がなく、複数回呼び出すと効率が低下するSetThreadPriority 可能性があります)。

于 2012-10-18T07:27:44.310 に答える
1

実はそんなに違うとは思いません。最初のケースでは:

static inline void ARRSpinLockLock(ARRSpinLock *l)
{
    unsigned y;
again:
    if (__builtin_expect(__sync_lock_test_and_set(l, 1), 0) == 0) {
        return;
    }
    for (y = 1000; y; y--) {
#if defined(__i386__) || defined(__x86_64__)
        asm("pause");
#endif
        if (*l == 0) goto again;
    }
    thread_switch(THREAD_NULL, SWITCH_OPTION_DEPRESS, 1);
    goto again;
}

ロックを取得しようとします。それが失敗した場合は、ループ内でスピンしfor、その間に使用可能になった場合は、すぐに再取得を試みます。そうでない場合は、CPUを放棄します。

その他の場合:

inline void Enter(void)
{
    int prev_s;
    do
    {
        prev_s = TestAndSet(&m_s, 0);
        if (m_s == 0 && prev_s == 1)
        {
            break;
        }
        // reluinquish current timeslice (can only
        // be used when OS available and
        // we do NOT want to 'spin')
        // HWSleep(0);
    }
    while (true);
}

の下のコメントに注意してくださいif。これは、OSがそのオプションを提供する場合、CPUをスピンまたは放棄できることを実際に示しています。実際、2番目の例は、その部分をプログラマーに任せているようです[ここにコードを続行するための好みの方法を挿入してください]。したがって、ある意味では、最初の例のような完全な実装ではありません。

私の全体的な見解は、最初のスニペットについてコメントしていますが、ロックを高速に取得できること(1000回の反復内)とCPUを過度に占有しないこと(したがって、ロックが使用可能にならない場合は、最終的に切り替えます)。

于 2012-10-18T07:23:32.903 に答える