Вопрос

Может ли кто-нибудь объяснить мне синхронизацию условий?

Пример (желательно на C#) также был бы очень признателен.

Это было полезно?

Решение

Похоже, ваш профессор говорит о многопоточности.Многопоточность позволяет компьютерным программам выполнять несколько действий одновременно.Запуск нового потока в то время, когда другой уже запущен, программисты называют «раскруткой потока».

Потоки могут использовать одно и то же пространство памяти.Синхронизация условий (или просто синхронизация) — это любой механизм, который защищает области памяти от одновременного изменения двумя разными потоками.

Допустим, вы ходите по магазинам, а жена дома оплачивает счета.Это наивный пример, и в реальной жизни он так не работает, но он послужит простой иллюстрацией.

Ваша жена оплачивает счет онлайн.В то же время вы проводите свою кредитную карту в продуктовом магазине.Оба действия включают в себя снятие денег с вашего текущего счета.Чтобы смоделировать это действие, мы напишем следующий код:

public class MyBanking
{
    static double myAccountBalance;
    //
    public void DebitAccount(double debitAmount)
    {
        Console.Writeline("Your Old Balance is: " + myAccountBalance.ToString());
        Console.Writeline("Your Debit is:       " + debitAmount.ToString());
        myAccountBalance = myAccountBalance - amount;
        Console.Writeline("Your New Balance is: " + myAccountBalance.ToString());
    }
}

Гипотетически, ваша жена запускает один экземпляр («копию») этого класса в одном потоке, а вы запускаете экземпляр в другом потоке.Переменная myAccountBalance объявлена ​​статической, что позволяет использовать ее совместно обоими запущенными экземплярами (у вас и вашей жены есть только один текущий счет).

Вы осуществляете дебет, вызывая такой код:

MyBanking bankingObject = new MyBanking();
bankingObject.DebitAccount(100);

Ваша жена вносит дебет в то же время:

MyBanking bankingObject = new MyBanking();
bankingObject.DebitAccount(50);

Что произойдет, если ваша беседа будет прервана беседой вашей жены после того, как ваш старый баланс будет напечатан на экране, но до того, как будет напечатан новый баланс?Тема вашей жены дебетует счет и возвращает управление обратно вашей теме.Ваша жена видит это на экране:

Your Old Balance is: 2000
Your Debit is:       50
Your New Balance Is: 1950

Когда компьютер напечатает новый баланс на вашем экране, это будет неправильно, потому что дебет вашей жены также будет учтен.Вы увидите что-то вроде этого:

Your Old Balance is: 2000
Your Debit is:       100
Your New Balance Is: 1850

Чтобы исправить это, мы окружаем код нашего метода оператором блокировки.Оператор блокировки заставляет все остальные потоки ждать завершения нашего экземпляра. Новый код выглядит следующим образом:

public class MyBanking
{
    static double myAccountBalance;
    //
    public void DebitAccount(double debitAmount)
    {
        lock (this)
        {
            Console.Writeline("Your Old Balance is: " + myAccountBalance.ToString());
            Console.Writeline("Your Debit is:       " + debitAmount.ToString());
            myAccountBalance = myAccountBalance - amount;
            Console.Writeline("Your New Balance is: " + myAccountBalance.ToString());
        }
    }
}

Поток вашей жены теперь будет ждать завершения выполнения вашего кода в операторе блокировки, прежде чем начнет выполняться код вашей жены.Ваш новый баланс теперь будет правильным, потому что поток вашей жены больше не сможет изменить баланс, пока вы завершаете ВАШУ транзакцию.На вашем экране вы теперь увидите это:

Your Old Balance is: 2000
Your Debit is:       100
Your New Balance Is: 1900

Ваша жена увидит это:

Your Old Balance is: 1900
Your Debit is:       50
Your New Balance Is: 1850

Это синхронизация.

Другие советы

По сути, это шаблон проектирования для потоков, которым требуется

а) синхронизировать доступ к ресурсу

б) иногда ждать других потоков, пока не будут выполнены определенные условия

Вы задаете этот вопрос в контексте C#, .NET обеспечивает поддержку этого с помощью Monitor.Wait и Monitor.Pulse (а также с помощью оболочек вокруг различных объектов Win32, таких как WaitEventhandle).

Вот хороший пример очереди на СО.

Основные технические детали выглядят так:

lock(buffer)  // is Monitor.Enter(buffer) ... finally Monitor.Leave(buffer)
{
   while (buffer.Count < 1)
   {
      Monitor.Wait(buffer); 
   }
   ...
}

Обратите внимание, что там есть функция «Подождите, пока заблокировано».Это похоже на тупик, но Wait снимет блокировку во время ожидания.Код внутри lock() { } по-прежнему имеет эксклюзивный доступ к буферу во время его работы.

И тогда другой поток должен сигнализировать, когда он помещает что-то в буфер:

Monitor.Pulse(buffer);

Приведенный выше код почти верен, но на самом деле неверен.Используя lock(this), вы заблокируете только свой экземпляр MyBanking класс, но твоя жена закроет свой.Чтобы заблокировать доступ к общей переменной, вы можете либо заблокировать тип (т.е. lock(typeof(MyBanking))) или вы можете ввести новую общую переменную и заблокировать ее (вы не можете заблокировать целое число, поэтому обычно люди создают объект следующим образом.

class MyBanking
{
    static object lockObj = new object();
    static double myAccountBalance;
    public void DebitAccount(double debitAmount)
    {
        lock (lockObj)

Синхронизация уже была четко объяснена.Однако, синхронизация условий конкретно диктует, что процесс/поток выполняется только после выполнения некоторого условия.Обычно условием является то, что какой-то другой процесс/поток уже выполнился.

В приведенном примере списание счета и просмотр баланса.Если бы просмотр вашего баланса был отдельным синхронизированным методом и мы хотели просмотреть баланс только после списания вашего счета, то для этого потребовалась бы синхронизация условий.

Синхронизация условий очень хорошо описывается проблема производителя и потребителя.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top