همزمانی قابل‌توسعه با ویژگی‌های Sync و Send

جالب است که زبان راست ویژگی‌های بسیار کمی برای همزمانی دارد. تقریباً هر ویژگی همزمانی که تاکنون در این فصل درباره آن صحبت کرده‌ایم بخشی از کتابخانه استاندارد بوده است، نه زبان. گزینه‌های شما برای مدیریت همزمانی محدود به زبان یا کتابخانه استاندارد نیستند؛ می‌توانید ویژگی‌های همزمانی خود را بنویسید یا از ویژگی‌هایی که دیگران نوشته‌اند استفاده کنید.

با این حال، دو مفهوم همزمانی در زبان تعبیه شده‌اند: ویژگی‌های std::marker به نام‌های Sync و Send.

اجازه انتقال مالکیت بین نخ‌ها با Send

ویژگی نشانگر Send نشان می‌دهد که مالکیت مقادیر نوعی که Send را پیاده‌سازی می‌کند می‌تواند بین نخ‌ها منتقل شود. تقریباً هر نوعی در راست Send است، اما برخی استثناها وجود دارند، از جمله Rc<T>: این نوع نمی‌تواند Send باشد زیرا اگر یک مقدار Rc<T> را کلون کنید و سعی کنید مالکیت کلون را به نخ دیگری منتقل کنید، هر دو نخ ممکن است شمارش ارجاع را هم‌زمان به‌روزرسانی کنند. به این دلیل، Rc<T> برای استفاده در شرایط تک‌ریسمانی طراحی شده است که نمی‌خواهید جریمه عملکرد ایمنی نخ را پرداخت کنید.

بنابراین، سیستم نوعی و محدودیت‌های ویژگی راست تضمین می‌کنند که هرگز به‌طور ناخواسته یک مقدار Rc<T> را به صورت ناایمن بین نخ‌ها ارسال نکنید. وقتی سعی کردیم این کار را در فهرست 16-14 انجام دهیم، خطای the trait Send is not implemented for Rc<Mutex<i32>> دریافت کردیم. وقتی به Arc<T> که Send است تغییر دادیم، کد کامپایل شد.

هر نوعی که به‌طور کامل از نوع‌های Send تشکیل شده باشد به‌طور خودکار به عنوان Send علامت‌گذاری می‌شود. تقریباً تمام نوع‌های اولیه Send هستند، به جز اشاره‌گر (Pointer)های خام، که در فصل 20 درباره آن‌ها صحبت خواهیم کرد.

اجازه دسترسی از چندین نخ با Sync

ویژگی نشانگر Sync نشان می‌دهد که نوعی که Sync را پیاده‌سازی می‌کند می‌تواند از چندین نخ به آن ارجاع داده شود. به عبارت دیگر، هر نوع T، Sync است اگر &T (یک ارجاع غیرقابل‌تغییر به T) Send باشد، به این معنی که ارجاع می‌تواند به صورت ایمن به نخ دیگری ارسال شود. مشابه Send، نوع‌های اولیه Sync هستند و نوع‌هایی که به طور کامل از نوع‌های Sync تشکیل شده‌اند نیز Sync هستند.

اسمارت پوینتر Rc<T> نیز به همان دلایلی که Send نیست، Sync هم نیست. نوع RefCell<T> (که در فصل 15 درباره آن صحبت کردیم) و خانواده نوع‌های مرتبط Cell<T> نیز Sync نیستند. پیاده‌سازی بررسی وام‌دهی که RefCell<T> در زمان اجرا انجام می‌دهد، برای نخ ایمن نیست. اسمارت پوینتر Mutex<T>، Sync است و می‌تواند برای اشتراک‌گذاری دسترسی بین چندین نخ استفاده شود، همانطور که در بخش «اشتراک یک Mutex<T> بین چندین نخ» مشاهده کردید.

پیاده‌سازی دستی Send و Sync ناایمن است

از آنجا که نوع‌هایی که از ویژگی‌های Send و Sync تشکیل شده‌اند به‌طور خودکار به‌عنوان Send و Sync علامت‌گذاری می‌شوند، ما نیازی به پیاده‌سازی دستی این ویژگی‌ها نداریم. به عنوان ویژگی‌های نشانگر، آن‌ها حتی هیچ متدی برای پیاده‌سازی ندارند. آن‌ها فقط برای اعمال اصول مربوط به همزمانی مفید هستند.

پیاده‌سازی دستی این ویژگی‌ها شامل پیاده‌سازی کد ناایمن در راست می‌شود. ما در فصل 20 درباره استفاده از کد ناایمن در راست صحبت خواهیم کرد؛ فعلاً، اطلاعات مهم این است که ساخت نوع‌های همزمان جدید که از قسمت‌های Send و Sync تشکیل نشده‌اند نیاز به دقت زیادی دارد تا اصول ایمنی رعایت شوند. “The Rustonomicon” اطلاعات بیشتری درباره این اصول و نحوه رعایت آن‌ها ارائه می‌دهد.

خلاصه

این آخرین باری نیست که در این کتاب با همزمانی روبه‌رو می‌شوید: کل فصل بعدی بر برنامه‌نویسی async تمرکز دارد، و پروژه در فصل 21 از مفاهیم این فصل در یک موقعیت واقعی‌تر نسبت به مثال‌های کوچک‌تر مطرح‌شده در اینجا استفاده خواهد کرد.

همانطور که قبلاً اشاره شد، به دلیل اینکه بخش بسیار کمی از نحوه مدیریت همزمانی در راست بخشی از زبان است، بسیاری از راه‌حل‌های همزمانی به‌عنوان crate پیاده‌سازی شده‌اند. این‌ها سریع‌تر از کتابخانه استاندارد تکامل می‌یابند، بنابراین حتماً به صورت آنلاین جستجو کنید تا crate‌های به‌روز و پیشرفته‌ای که برای موقعیت‌های چندریسمانی مناسب هستند را پیدا کنید.

کتابخانه استاندارد راست کانال‌هایی برای ارسال پیام و انواع اسمارت پوینتر، مانند Mutex<T> و Arc<T>، فراهم می‌کند که استفاده از آن‌ها در زمینه‌های همزمان ایمن است. سیستم نوعی و کنترل‌کننده وام‌دهی تضمین می‌کنند که کدی که از این راه‌حل‌ها استفاده می‌کند با رقابت‌های داده یا ارجاع‌های نامعتبر مواجه نمی‌شود. هنگامی که کد شما کامپایل شود، می‌توانید مطمئن باشید که بدون آن دسته از اشکال‌های سخت‌ردیابی که در زبان‌های دیگر معمول است، به خوبی روی چندین نخ اجرا خواهد شد. برنامه‌نویسی همزمان دیگر مفهومی برای ترسیدن نیست: پیش بروید و برنامه‌های خود را بی‌باکانه همزمان کنید!