پیاده سازی Synchronization در سی شارپ

تیم تحریریه 1403/12/20 0 137
لینک کوتاه https://zoheirsoftware.com/z/fba24dbb8 |
پیاده سازی Synchronization در سی شارپ,مشکلات همزمان‌سازی در سی شارپ,روش‌های Synchronization در #C

پیاده سازی Synchronization در سی شارپ

در برنامه‌نویسی چندنخی (Multithreading) در سی شارپ، زمانی که چندین Thread به یک منبع مشترک (مانند یک متغیر یا فایل) دسترسی دارند، ممکن است مشکلاتی مانند Race Condition، Deadlock و Data Corruption رخ دهد.

برای جلوگیری از این مشکلات، از Synchronization (همگام‌سازی) استفاده می‌شود تا اطمینان حاصل شود که فقط یک Thread در هر لحظه می‌تواند به بخش‌های حساس کد دسترسی داشته باشد.

روش‌های مختلفی برای پیاده‌سازی Synchronization در سی شارپ وجود دارد، از جمله استفاده از lock، Mutex، Semaphore و Monitor که هرکدام کاربرد خاصی دارند.

مثلاً، کلمه کلیدی lock برای محدود کردن اجرای یک بخش از کد توسط یک Thread در لحظه استفاده می‌شود.

Mutex نیز عملکرد مشابهی دارد، اما می‌تواند در بین فرآیندهای مختلف (Processes) نیز به اشتراک گذاشته شود.

Semaphore برای کنترل تعداد Threadهایی که به یک منبع خاص دسترسی دارند، استفاده می‌شود.

همچنین، کلاس Monitor قابلیت‌های پیشرفته‌تری برای مدیریت همگام‌سازی ارائه می‌دهد.

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

 

 

پیاده سازی Synchronization در سی شارپ

مشکلات همزمان‌سازی در سی شارپ

  • Race Condition

    این مشکل زمانی رخ می‌دهد که چند نخ به طور همزمان به داده‌ها دسترسی دارند و ترتیب اجرای نخ‌ها باعث بروز نتایج ناخواسته می‌شود.
  • Deadlock

    زمانی که دو یا چند نخ منتظر منابعی هستند که در اختیار یکدیگر قرار دارند، باعث می‌شود هیچ کدام از نخ‌ها نتوانند پیش بروند و در وضعیت بن‌بست قرار می‌گیرند.
  • Starvation

    در این حالت، یک نخ به دلیل اولویت‌بندی‌های نادرست یا قفل‌ها به طور دائم قادر به اجرا نمی‌شود.

اهداف Synchronization

  • ایمنی داده‌ها

    جلوگیری از دسترسی هم‌زمان و اشتباه به داده‌ها.
  • کنترل منابع

    مدیریت منابع سیستم به طور مؤثر.
  • افزایش کارایی

    جلوگیری از بروز مشکلاتی که باعث کاهش کارایی می‌شود.

روش‌های Synchronization در #C

  •  استفاده از Lock

    یکی از روش‌های ساده و متداول برای همزمان‌سازی در سی‌شارپ استفاده از کلمه کلیدی lock است.

    این کلمه کلیدی برای جلوگیری از دسترسی هم‌زمان به یک بخش از کد توسط نخ‌های مختلف استفاده می‌شود.

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

مثال استفاده از Lock:

class Program

{

    private static int counter = 0;

    private static readonly object lockObject = new object();




    static void Main(string[] args)

    {

        Task.Run(() => IncrementCounter());

        Task.Run(() => IncrementCounter());

        Task.WaitAll();




        Console.WriteLine("Final Counter Value: " + counter);

    }




    static void IncrementCounter()

    {

        for (int i = 0; i < 1000; i++)

        {

            lock (lockObject)  // Synchronization block

            {

                counter++;

            }

        }

    }

}

در این مثال، برای اطمینان از اینکه متغیر counter به طور هم‌زمان توسط نخ‌های مختلف تغییر نمی‌کند، از کلمه کلیدی lock استفاده شده است.

lockObject به عنوان شی‌ء قفل عمل می‌کند.

  • استفاده از Monitor

    کلاس Monitor در سی‌شارپ نیز برای همزمان‌سازی نخ‌ها مورد استفاده قرار می‌گیرد و عملکردی مشابه به lock دارد، اما با امکانات بیشتری نظیر قابلیت Timeout و قابلیت ارسال سیگنال به نخ‌های دیگر.

مثال استفاده از Monitor:

class Program

{

    private static int counter = 0;

    private static readonly object lockObject = new object();




    static void Main(string[] args)

    {

        Task.Run(() => IncrementCounter());

        Task.Run(() => IncrementCounter());

        Task.WaitAll();




        Console.WriteLine("Final Counter Value: " + counter);

    }




    static void IncrementCounter()

    {

        for (int i = 0; i < 1000; i++)

        {

            Monitor.Enter(lockObject);

            try

            {

                counter++;

            }

            finally

            {

                Monitor.Exit(lockObject);

            }

        }

    }

}

در این مثال، به جای استفاده از lock، از Monitor.Enter و Monitor.Exit برای قفل کردن و باز کردن منابع استفاده شده است.

این روش به صورت دستی کنترل بیشتری به ما می‌دهد.

 

 

آیا به دنبال یک فرصت عالی برای یادگیری برنامه‌نویسی هستید؟ 🚀

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

👨‍🏫 چرا دوره ما را انتخاب کنید؟

  • محتوای جامع و عملی: با پروژه‌های واقعی و تمرینات عملی، یادگیری را به تجربه‌ای جذاب تبدیل کنید.
  • مدرس مجرب: از تجربه و دانش مدرس حرفه‌ای بهره‌مند شوید که شما را در هر مرحله از یادگیری راهنمایی می‌کنند.
  • پشتیبانی ۲۴/۷: هر زمان که سوالی داشتید، ما در کنار شما خواهیم بود تا به شما کمک کنیم.
  • دسترسی مادام‌العمر: به محتوای دوره دسترسی دائمی داشته باشید و هر زمان که خواستید، می‌توانید به آن مراجعه کنید.

💡 فرصت را از دست ندهید!

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

همین امروز به جمع یادگیرندگان ما بپیوندید و اولین قدم را به سوی آینده‌ای روشن‌تر بردارید!

شرکت در دوره آموزش برنامه نویسی سی شارپ

 

 

 

 

  • استفاده از Mutex

    Mutex به نوعی قفل سیستمی است که می‌تواند بین فرآیندهای مختلف نیز به اشتراک گذاشته شود.
    این ابزار بیشتر در برنامه‌هایی که نیاز به همزمان‌سازی میان فرآیندهای مختلف دارند کاربرد دارد.

مثال استفاده از Mutex:

class Program

{

    static Mutex mutex = new Mutex();




    static void Main(string[] args)

    {

        Task.Run(() => AccessResource());

        Task.Run(() => AccessResource());

        Task.WaitAll();

    }




    static void AccessResource()

    {

        mutex.WaitOne();  // Request ownership of the mutex

        try

        {

            Console.WriteLine("Resource is being accessed.");

            Thread.Sleep(1000);

        }

        finally

        {

            mutex.ReleaseMutex();  // Release ownership of the mutex

        }

    }

}

در این مثال، از Mutex برای همزمان‌سازی دسترسی به منابع مشترک استفاده شده است.

  • استفاده از Semaphore

    Semaphore یکی دیگر از ابزارهای همزمان‌سازی است که تعداد خاصی از نخ‌ها می‌توانند به طور همزمان به منابع دسترسی داشته باشند.
    این ابزار برای کنترل دسترسی به منابع محدود مفید است.

مثال استفاده از Semaphore:

class Program

{

    static Semaphore semaphore = new Semaphore(2, 2);  // Maximum 2 threads can access the resource at once.




    static void Main(string[] args)

    {

        Task.Run(() => AccessResource());

        Task.Run(() => AccessResource());

        Task.Run(() => AccessResource());

        Task.WaitAll();

    }




    static void AccessResource()

    {

        semaphore.WaitOne();  // Request access to the resource

        try

        {

            Console.WriteLine("Resource is being accessed.");

            Thread.Sleep(1000);

        }

        finally

        {

            semaphore.Release();  // Release the resource

        }

    }

}

در این مثال، فقط دو نخ می‌توانند به طور همزمان به منبع دسترسی داشته باشند.

 

روش‌های Synchronization در #C

نکات مهم در استفاده از Synchronization

  • اجتناب از قفل‌های طولانی

    هنگام استفاده از قفل‌ها باید مراقب بود که نخ‌ها برای مدت طولانی در داخل قفل باقی نمانند.
    قفل‌های طولانی می‌توانند منجر به کاهش کارایی و همچنین بروز مشکلاتی مانند Deadlock شوند.
  • اجتناب از Nested Locks

    استفاده از قفل‌های تو در تو می‌تواند باعث بروز مشکلاتی مانند Deadlock شود.
  • استفاده از تکنیک‌های غیرهمزمان (Asynchronous)

    در برخی موارد می‌توان از برنامه‌نویسی غیرهمزمان (Async) برای مدیریت همزمانی استفاده کرد.

 

نکات مهم در استفاده از Synchronization

 

مثال پروژه محور از پیاده سازی Synchronization

پروژه: سیستم حسابداری با همزمان‌سازی

در این پروژه، یک کلاس BankAccount داریم که امکان واریز و برداشت وجه را فراهم می‌کند.

چندین نخ به صورت هم‌زمان می‌توانند عملیات واریز و برداشت را انجام دهند.

برای جلوگیری از مشکلات همزمانی، از lock برای همزمان‌سازی استفاده می‌کنیم.

گام‌های پیاده‌سازی

  •  ایجاد کلاس BankAccount

    این کلاس دارای متدهای Deposit و Withdraw است که به ترتیب برای واریز وجه و برداشت وجه از حساب استفاده می‌شود.
    برای اطمینان از اینکه عملیات‌ها به صورت هم‌زمان اجرا نمی‌شوند، از lock استفاده می‌کنیم.
using System;

using System.Threading;

class BankAccount

{

    private decimal balance = 0;

    private readonly object lockObject = new object();


    // واریز وجه

    public void Deposit(decimal amount)

    {

        lock (lockObject)  // استفاده از قفل برای همزمان‌سازی

        {

            if (amount > 0)

            {

                balance += amount;

                Console.WriteLine($"Deposit {amount} - New Balance: {balance}");

            }

            else

            {

                Console.WriteLine("Deposit amount must be positive.");

            }

        }

    }


    // برداشت وجه

    public void Withdraw(decimal amount)

    {

        lock (lockObject)  // استفاده از قفل برای همزمان‌سازی

        {

            if (amount > 0 && amount <= balance)

            {

                balance -= amount;

                Console.WriteLine($"Withdraw {amount} - New Balance: {balance}");

            }

            else

            {

                Console.WriteLine("Insufficient balance or invalid amount.");

            }

        }

    }


    // نمایش موجودی

    public void DisplayBalance()

    {

        Console.WriteLine($"Current Balance: {balance}");

    }

}
  •  استفاده از نخ‌ها برای انجام عملیات

    در این مرحله، نخ‌ها برای واریز و برداشت وجه به صورت هم‌زمان فراخوانی می‌شوند.
    برای شبیه‌سازی شرایط رقابتی، نخ‌ها به صورت هم‌زمان تلاش می‌کنند تا مقادیر مختلفی را به حساب واریز و یا از آن برداشت کنند.
using System;

using System.Threading;


class Program

{
    static void Main(string[] args)

    {
        BankAccount account = new BankAccount();


        // ایجاد چند نخ برای واریز و برداشت همزمان

        Thread thread1 = new Thread(() => PerformTransactions(account));

        Thread thread2 = new Thread(() => PerformTransactions(account));



        // شروع نخ‌ها

        thread1.Start();

        thread2.Start();


        // منتظر ماندن تا پایان اجرای نخ‌ها

        thread1.Join();

        thread2.Join();


        // نمایش موجودی نهایی

        account.DisplayBalance();

    }


    // تابع برای انجام واریز و برداشت

    static void PerformTransactions(BankAccount account)

    {

        // واریز مبلغ به حساب

        account.Deposit(1000);

        Thread.Sleep(100); // وقفه برای شبیه‌سازی تاخیر



        // برداشت مبلغ از حساب

        account.Withdraw(500);

        Thread.Sleep(100); // وقفه برای شبیه‌سازی تاخیر


        // واریز مجدد به حساب

        account.Deposit(2000);

        Thread.Sleep(100); // وقفه برای شبیه‌سازی تاخیر


        // برداشت مبلغ نهایی

        account.Withdraw(1500);

    }

}

توضیح کد

  • در این کد، کلاس BankAccount دارای یک متغیر balance است که موجودی حساب را نگهداری می‌کند.

  • دو متد Deposit و Withdraw برای واریز و برداشت پول به حساب طراحی شده‌اند.

  • در هر دو متد، برای اطمینان از دسترسی هم‌زمان نخ‌ها به موجودی حساب از کلمه کلیدی lock استفاده شده است.

  • در Main چندین نخ به طور هم‌زمان فراخوانی می‌شود که عملیات واریز و برداشت را انجام می‌دهند.

  • در نهایت، بعد از اتمام همه نخ‌ها، موجودی نهایی حساب با استفاده از DisplayBalance نمایش داده می‌شود.

 خروجی پیش‌بینی شده

با اجرای این برنامه، به دلیل استفاده از قفل‌ها (Locks)، عملیات‌ها به صورت هماهنگ و بدون تداخل اجرا خواهند شد و نتیجه‌ی نهایی به درستی محاسبه خواهد شد.

Deposit 1000 - New Balance: 1000

Withdraw 500 - New Balance: 500

Deposit 2000 - New Balance: 2500

Withdraw 1500 - New Balance: 1000

Deposit 1000 - New Balance: 2000

Withdraw 500 - New Balance: 1500

Deposit 2000 - New Balance: 3500

Withdraw 1500 - New Balance: 2000

Current Balance: 2000
دوره های مرتبط
آموزش برنامه نویسی سی شارپ,آموزش پروژه محور سی شارپ,آموزش مقدماتی تا پیشرفته سی شارپ,طراحی نرم افزار تحت ویندوز

آموزش برنامه نویسی سی شارپ

زبان شی گرایی حرفه ای سی شارپ یک زبان قدرتمند برای طراحی نرم افزار به شمار میرود.

999,000 تومان

2.7k بازدید

ارسال دیدگاه

برای ارسال نظر لطفا ورود یا ثبت نام کنید.