التزامن: أطلق والقنوات
تقدّم لغة ص تزامنًا على نمط Go: خيوط خفيفة تُطلَق بكلمة أطلق، وتتواصل عبر
قنوات بدل الذاكرة المشتركة، مع أدوات مزامنة (مجموعة انتظار، قفل، مستقبل)
وجملة اختر للاختيار بين قنوات.
الخيوط الخفيفة: أطلق
تُطلق أطلق استدعاءَ دالّة أو كتلةً كاملة في خيط خفيف يعمل بالتوازي:
دالة حساب_مربع(ق، قيمة)
ق.أرسل(قيمة * قيمة)
نهاية
متغير ق = قناة(5)
أطلق حساب_مربع(ق، 3)
أطلق حساب_مربع(ق، 4)
انتظر_الكل()
وبصيغة الكتلة (تنتهي بـنهاية):
متغير م = مستقبل()
أطلق
متغير مجموع = 0
لكل ن في 1..10
مجموع = مجموع + ن
نهاية
م.عيّن(مجموع)
نهاية
اطبع_سطر(م.احصل())
55
انتظر_الكل()تحجب حتى تنتهي كلّ الخيوط المُطلَقة.- الترتيب غير مضمون بين الخيوط — اجمع النتائج عبر قناة ثم رتّبها إن لزم الترتيب.
⚠️ تباعُد مترجم مفتوح (
ISSUE-072):أطلقبسطرٍ واحد يُرسِل مباشرةً عبر قناة (أطلق ق.أرسل(4)) لا يُطلق الخيط في المترجم (بينما يعمل في المفسّر)؛ استعمل صيغة الكتلةأطلق ... نهايةالتي تعمل مزدوجًا بثبات.
القنوات
القناة أنبوب FIFO آمن بين الخيوط، تُنشأ بـقناة(سعة) (قناة مخزّنة بسعةٍ محدّدة):
متغير ق = قناة(5)
ق.أرسل(10)
ق.أرسل(20)
ق.أرسل(30)
اطبع_سطر(ق.استقبل())
اطبع_سطر(ق.استقبل())
اطبع_سطر(ق.الحجم())
اطبع_سطر(ق.فارغة())
10
20
1
خطأ
| الطريقة | المعنى |
|---|---|
أرسل(قيمة) | إرسال إلى القناة |
استقبل() | استقبال (بترتيب الإرسال FIFO) |
الحجم() | عدد العناصر المنتظرة |
فارغة() | هل القناة فارغة؟ |
أغلق() / مغلقة() | إغلاق القناة / فحص الإغلاق |
حاول_ارسل(قيمة) / حاول_استقبل() | إرسال/استقبال غير حاجب |
أرسل_بمهلة(قيمة، مللي) / استقبل_بمهلة(مللي) | إرسال/استقبال بمهلة قصوى |
السعة() | سعة القناة القصوى |
نمط شائع — إرسال ثم إغلاق ثم تفريغ:
متغير ق = قناة(5)
ق.أرسل(1)
ق.أرسل(2)
ق.أغلق()
بينما (ليس ق.فارغة())
اطبع_سطر(ق.استقبل())
نهاية
الاختيار بين القنوات: اختر
تنتقي اختر أوّل فرعٍ قناتُه جاهزة — نظير select في Go:
متغير ق = قناة(1)
ق.أرسل(1)
اختر
عندما ق.استقبل():
اطبع_سطر("جاهز")
نهاية
أدوات المزامنة
مجموعة الانتظار
عدّاد مهامّ: أضف(n) قبل الإطلاق، وأنهي() من كلّ خيط عند اكتماله، وانتظر()
تحجب حتى يصل العدّاد إلى الصفر:
متغير مج = مجموعة_انتظار()
متغير ق = قناة(100)
مج.أضف(50)
لكل _ في 1..50
أطلق
ق.أرسل(1)
مج.أنهي()
نهاية
نهاية
مج.انتظر()
اطبع_سطر(ق.الحجم())
50
القفل
قفل استبعاد متبادل (mutex) لحماية حالة مشتركة:
متغير ق_ف = قفل()
اطبع_سطر(ق_ف.مقفل())
ق_ف.اقفل()
اطبع_سطر(ق_ف.مقفل())
ق_ف.افتح()
خطأ
صحيح
كما تتوفّر حاول_قفل() — محاولة قفل غير حاجبة تُرجع نجاحها فورًا.
فضّل تمرير البيانات عبر القنوات على مشاركة الحالة خلف قفل — على المأثور الشائع في مجتمع Go: «لا تتواصل بمشاركة الذاكرة؛ شارك الذاكرة بالتواصل».
المستقبل
قيمة واحدة تُنتَج لاحقًا: عيّن(قيمة) من الخيط المُنتِج، واحصل() تحجب حتى
الجاهزيّة، وجاهز() فحص غير حاجب:
متغير م = مستقبل()
اطبع_سطر(م.جاهز())
م.عيّن(42)
اطبع_سطر(م.جاهز())
اطبع_سطر(م.احصل())
خطأ
صحيح
42
غير المتزامن غير_متزامن/انتظر
إلى جانب نمط Go توجد كلمتا غير_متزامن (async) وانتظر (await) للدوالّ غير
المتزامنة — راجع ميزات متقدّمة.