σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyخرائط الطريقالمسارات
Ctrl K
AO
+1.2k متعلّم
تسجيل الدخولانضم ↗
خرائط الطريقالمسارات
AO
+1.2k متعلّم
تسجيل الدخول
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyخرائط الطريقالمسارات
Ctrl K
AO
+1.2k متعلّم
تسجيل الدخولانضم ↗
خرائط الطريقالمسارات
AO
+1.2k متعلّم
تسجيل الدخول
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
مسار Lock-free›الوحدة 2 · الذرّيات والترتيب والضمانات›الموضوع 2.3·~45 دمتقدم

ضمانات التقدم: من بلا عرقلة إلى بلا انتظار

الموضع في المسارالوحدة 2 من 4 · الموضوع 3 من 3
2.3 ضمانات التقدم: من بلا عرقلة إلى بلا انتظار
—درجة المختبر— / 100إجمالي XP—التتابع—

4 دقيقة قراءة4 أمثلة برمجية

  1. 01خيط واحد متوقف
  2. 02بلا أقفال: دائمًا ينتهي أحدهم
  3. 03بلا انتظار: الجميع ينتهي
  4. 04ما ستبنيه

ثلاثة عدّادات تعطي الجواب الصحيح تحت كل الجداول ومع ذلك ليست متماثلة. أوقف خيطًا في أسوأ لحظة فيوقف القفل الدوّار الجميع ويسمح عدّاد المقارنة والتبديل بمرور أحدهم ويتيح عدّاد fetch-and-add لكل خيط أن ينتهي في دور واحد. هذه هي درجات سلّم ضمانات التقدم الثلاث.

01

خيط واحد متوقف

يستطيع نظام التشغيل الحقيقي أن ينزع خيطًا عن نواته في أي لحظة: تنتهي شريحة وقته أو يرسله خطأ صفحة إلى القرص أو تصل مقاطعة. ينبغي أن تنجو البنية المتزامنة الجيدة من ذلك. نحدد السؤال بخصم: ينفّذ prefix من الأدوار يختاره ثم يوقف خيطًا إلى الأبد ونعطي budget من الجولات لكل الباقين. فإن بقي خيط غير موقوف لم ينتهِ فيمكن إيقاف البنية. يفشل القفل الدوّار في هذا الاختبار بأبسط طريقة: إن أوقف الخصم الخيط الذي يمسك القفل دار الآخرون حتى ينتهي الميزانية.

main.pyPython
def locked_increments(k):    def thread(shared):        for _ in range(k):            while True:                yield                if not shared.get("lock", 0):                    shared["lock"] = 1                    break            yield            value = shared.get("x", 0)            yield            shared["x"] = value + 1            yield            shared["lock"] = 0    return threaddef progress_without(make_threads, prefix, paused, budget=50):    n = len(make_threads({}))    allowed = [tid for tid in range(n) if tid not in paused]    _, alive = run_prefix(make_threads, list(prefix) + allowed * budget)    return [tid for tid in allowed if tid not in alive]lk = lambda shared: [locked_increments(1)(shared), locked_increments(1)(shared)]print(run_prefix(lk, [0]))print("thread 0 paused holding the lock:", progress_without(lk, [0], [0]))print("thread 0 finished first:         ", progress_without(lk, [0, 0, 0, 0], [0]))
({'lock': 1}, [0, 1])
thread 0 paused holding the lock: []
thread 0 finished first:          [1]

بعد دور واحد يمسك الخيط 0 القفل ('lock': 1). أوقفه هناك فلا ينهي الخيط 1 شيئًا في خمسين جولة: []. دعه ينفّذ أدواره الأربعة أولًا فيتحرر القفل ثانية وينتهي الخيط 1: [1]. الفرق هو مكان ضربة الخصم فقط. يحوّل القفل أي توقف داخل المقطع الحرج إلى توقف للبرنامج كله.

02

بلا أقفال: دائمًا ينتهي أحدهم

تؤتمت is_blocking الخصم. تجرّب كل بادئة من بضعة أدوار وتوقف كل خيط حي بدوره وتسأل progress_without هل ما زال الباقون ينتهون. وفي القفل الدوّار الجواب نعم بعد دور واحد. أما في عدّاد المقارنة والتبديل فلا أبدًا: الخيط الموقوف بين قراءته وتبديله يترك القيمة دون تغيير فينجح تبديل الخيط الآخر. هذا هو تعريف بلا أقفال: النظام ككل يتقدم دائمًا حتى لو أُوقف خيط إلى الأبد.

main.pyPython
def is_blocking(make_threads, depth=3, budget=50):    def visit(prefix):        _, alive = run_prefix(make_threads, prefix)        for paused in alive:            finished = progress_without(make_threads, prefix, [paused], budget)            if len(finished) < len([tid for tid in range(len(make_threads({}))) if tid != paused]):                return True        if len(prefix) < depth:            return any(visit(prefix + [tid]) for tid in alive)        return False    return visit([])cs = lambda shared: [cas_increments(1)(shared), cas_increments(1)(shared)]at = lambda shared: [atomic_increments(1)(shared), atomic_increments(1)(shared)]print("spin lock:", is_blocking(lk))print("compare-and-swap:", is_blocking(cs))print("fetch-and-add:", is_blocking(at))
spin lock: True
compare-and-swap: False
fetch-and-add: False

عدّاد المقارنة والتبديل وعدّاد fetch-and-add كلاهما غير حاجب. وللسلّم درجة ثالثة لأن «بلا أقفال» ما زال يسمح بيوم سيئ لخيط واحد: قد يخسر كل السباقات.

03

بلا انتظار: الجميع ينتهي

للعملية بلا انتظار حدّ على أدوارها لا يستطيع أي جار تجاوزه. تقيسه worst_own_turns: أكبر عدد أدوار يأخذه خيط عبر كل الجداول الكاملة. ثم تطرح classify السؤال الحاسم. هل يبقى أسوأ حالات الخيط 0 نفسه حين يكون لجاره زيادة واحدة وحين يكون له ثلاث؟ إن بقي فالخيط 0 بلا انتظار. وإن نما فبوسع الجار أن يجعل الخيط 0 يعيد المحاولة أكثر فالبنية بلا أقفال فقط.

main.pyPython
def worst_own_turns(make_threads, tid):    worst = 0    def visit(prefix):        nonlocal worst        _, alive = run_prefix(make_threads, prefix)        if not alive:            worst = max(worst, prefix.count(tid))            return        for other in alive:            visit(prefix + [other])    visit([])    return worstdef classify(factory, others=(1, 3)):    def program(m):        return lambda shared: [factory(1)(shared), factory(m)(shared)]    if is_blocking(program(others[0])):        return "blocking"    light, busy = worst_own_turns(program(others[0]), 0), worst_own_turns(program(others[1]), 0)    return "wait-free" if light == busy else "lock-free"for neighbour in (1, 2, 3):    cas = lambda shared: [cas_increments(1)(shared), cas_increments(neighbour)(shared)]    atomic = lambda shared: [atomic_increments(1)(shared), atomic_increments(neighbour)(shared)]    print(neighbour, "increments next door: CAS", worst_own_turns(cas, 0), "turns, fetch-and-add", worst_own_turns(atomic, 0))print([classify(f) for f in (locked_increments, cas_increments, atomic_increments)])
1 increments next door: CAS 4 turns, fetch-and-add 1
2 increments next door: CAS 6 turns, fetch-and-add 1
3 increments next door: CAS 8 turns, fetch-and-add 1
['blocking', 'lock-free', 'wait-free']
أيها نختار

أقوى ما في السلّم وأكلفه تصميمًا هو بلا انتظار ويبين fetch-and-add أنه ليس بعيد المنال دائمًا. وبلا أقفال هو الهدف العملي للطوابير والمكدسات. القفل مقبول حيث لا يضرك حامل موقوف لكنه غير مقبول أبدًا على مسار يجب ألا يتوقف.

main.pyPython
returns = [float(r) for r in load_bars()["close"].pct_change().dropna()][:6]ups = [sum(1 for r in returns[start::2] if r > 0) for start in (0, 1)]for name, factory in (("locked", locked_increments), ("cas", cas_increments), ("atomic", atomic_increments)):    program = lambda shared, f=factory: [f(k)(shared) for k in ups]    blocking = is_blocking(program)    print(name, classify(factory), blocking, None if blocking else worst_own_turns(program, 0))
locked blocking True None
cas lock-free False 8
atomic wait-free False 1
ما تقوله البيانات الحقيقيةأيام الصعود في أول 6 عوائد لـSPY: زيادة واحدة للخيط 0 وثلاث للخيط 1
قفل دوّارblockingخيط موقوف يوقف الآخر
المقارنة والتبديلlock-freeأسوأ حالة للخيط 0: 8 أدوار
fetch-and-addwait-freeأسوأ حالة للخيط 0: دور واحد
أسوأ عدد أدوار للخيط 0 حسب عمل الجار
fetch-and-add، 3 زيادات للجار1
CAS، زيادة واحدة للجار4
CAS، زيادتان للجار6
CAS، 3 زيادات للجار8

اقرأ الأعمدة: يحتاج خيط fetch-and-add إلى دور واحد مهما انشغل جاره بينما يحتاج خيط المقارنة والتبديل إلى 4 ثم 6 ثم 8 أدوار كلما زادت زيادات الجار. يمكن لكل زيادة إضافية عند الجار أن تجعل الخيط 0 يخسر سباقًا آخر ويكرر قراءته وتبديله. هذا النمو هو بالضبط ما يفصل بلا أقفال عن بلا انتظار.

تعريفضمانات التقدم

حاجب: خيط موقوف يستطيع إيقاف الباقين. بلا أقفال: ينتهي خيط ما دائمًا. بلا انتظار: ينتهي كل خيط في عدد محدود من أدواره. كل مستوى يستلزم الذي قبله في هذه القائمة.

04

ما ستبنيه

يتبع المختبر الدرس: عدّاد القفل الدوّار والتشغيل مع إيقاف بعض الخيوط والاختبار الذي يقول هل يمكن لإيقاف خيط أن يوقف الباقين وأسوأ حالات أدوار الخيط الخاصة وتصنيف عدّاد ودراسة العدّادات الثلاثة على أيام صعود SPY.

  • الدالة · السؤالتعتمد على
  • locked_increments(k)عدّاد ينتظر قفلًا؟حساب بسيط
  • progress_without(make_threads, prefix, paused, budget)من ينتهي إن أُوقفت بعض الخيوط؟run_prefix
  • is_blocking(make_threads, depth, budget)هل يستطيع خيط موقوف إيقاف الجميع؟progress_without
  • worst_own_turns(make_threads, tid)كم دورًا قد يحتاج خيط؟run_prefix
  • classify(factory, others)حاجب أم بلا أقفال أم بلا انتظار؟is_blockingworst_own_turns
  • study(bars)أين تقف العدّادات الثلاثة على SPY؟classifyis_blockingworst_own_turns

أهم الخلاصات

  • القفل قد يوقف الجميع. أوقف الحامل بعد دور واحد فلا ينهي الخيط الآخر شيئًا في خمسين جولة.
  • بلا أقفال تعني أن أحدهم ينتهي دائمًا. لكن قد يخسر خيط كل السباقات: تحتاج المقارنة والتبديل إلى 4 و6 و8 أدوار كلما عمل الجار أكثر.
  • بلا انتظار له حدّ لا يكسره جار. ينتهي fetch-and-add في دور واحد مهما فعل الجار.
تحقق سريع
يؤدي خيط زيادة واحدة بالمقارنة والتبديل بينما يؤدي آخر 5 زيادات. أي عبارة مضمونة؟
اختر إجابة.

الموضوع التالي: تعرف الآن ما يمكن أن يعد به طابور. مخزن حلقي لمنتج واحد ومستهلك واحد يبني أبسط طابور مفيد بلا أقفال بكاتب واحد وقارئ واحد وذاكرة ثابتة ودون أي قراءة وتعديل وكتابة ذرّية ويتحقق المستكشف أنه لا يضيّع تيكًا ولا يعيد ترتيبه أبدًا.

المختبر: ما الذي يُقيَّم

6 مهام · 100 نقطة
  • عدّاد على قفل دوّار10 نقطة
  • التشغيل مع خيوط موقوفة20 نقطة
  • هل يوقف توقف واحد الجميع20 نقطة
  • أسوأ حالة لخيط15 نقطة
  • تسمية الضمان10 نقطة
  • الدراسة على جدول SPY25 نقطة
المستكشف · lab-lf-05
▾ lab-lf-05
▾ data
…
bash · داخل المتصفح
learner@quantcraft:~/lab-lf-05$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

هل تريد إعادة ضبط هذا الموضوع؟

سيعود كل ما في lab-lf-05 إلى الملفات الابتدائية وستُمسح الطرفية. ستفقد حلّك الحالي ولا يمكن التراجع عن ذلك.

سيُعاد ضبطه
  • main.py ← الشيفرة الابتدائية
  • سجل الطرفية ومخرجات الاختبارات
  • التغييرات غير المُرسلة
سيُحتفظ به
  • أفضل درجة في المختبر
  • نقاط XP والتتابع
  • تقدّم المحاضرة والملاحظات