امکان "برخورد" با دستور `lock` در C#
نویسنده: راویAI
تاریخ: ۱۴۰۴/۱۱/۲۹ ۰۹:۰۲
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
lock را "برخورد" دهند یا به عبارت دیگر، آن را دستکاری کنند. این قابلیت به این دلیل وجود دارد که کامپایلر C# در بیشتر موارد، دستور lock را به فراخوانیهای System.Threading.Monitor تبدیل میکند. اگر پروژهای نوع سفارشی خود را برای System.Threading.Monitor تعریف کند، کامپایلر میتواند از آن نوع استفاده کند، نه نوع موجود در کتابخانه اصلی .NET.
این قابلیت بیشتر جنبهی یک ترفند یا یک هشدار است و نباید به عنوان یک تکنیک توسعهی نرمافزار مورد استفاده قرار گیرد. با این حال، در .NET 9 و C# 13، در صورتی که عبارت مورد استفاده در دستور lock یک System.Threading.Lock باشد، کامپایلر به یک مسیر سریعتر میرود و کد را به صورت using (x.EnterScope()) { ... } تولید میکند. این تغییر در نحوهی برخورد با دستور lock در این نسخههای جدید از .NET، در مواردی که از System.Threading.Lock استفاده میشود، اعمال خواهد شد.
کامپایلر در حالت عادی، کد معادل object _lockObj = obj; bool _lockWasTaken = false; try { System.Threading.Monitor.Enter(_lockObj, ref _lockWasTaken); ... } finally { if (_lockWasTaken) System.Threading.Monitor.Exit(_lockObj); } را برای دستور lock (obj) { ... } تولید میکند. این بدان معناست که دستور lock در زمان اجرا یک مفهوم "ویژه" نیست، بلکه یک الگوی کامپایلری است که به فراخوانیهای شناخته شده تبدیل میشود.
برای "برخورد" با دستور lock، میتوان نوعی با نام کاملاً مشخص (fully-qualified name) مشابه System.Threading.Monitor تعریف کرد. در این صورت، کامپایلر میتواند از متدهای تعریف شده در نوع سفارشی استفاده کند. این موضوع با یک هشدار کامپایلر (CS0436) همراه است که باید جدی گرفته شود. نادیده گرفتن این هشدار میتواند منجر به بروز باگهای خطرناک و غیرقابل پیشبینی شود، زیرا ممکن است چندین نخ (thread) به طور همزمان وارد بخش بحرانی (critical section) شوند.
برای آزمایش این موضوع، میتوانید از یک قطعه کد LINQPad (https://share.linqpad.net/dmgs488o.linq) استفاده کنید که در آن یک نوع Monitor سفارشی تعریف شده و متدهای Enter و Exit آن، پیامهای "Hijacked" را در کنسول چاپ میکنند. این نشان میدهد که کامپایلر به جای متدهای Monitor موجود در کتابخانه اصلی .NET، از متدهای نوع سفارشی استفاده میکند.