Поточная обработка C#: Использование монитора. Ожидайте, блокировка и PulseAll

Я думаю, что Вы немного неправильно поняли мою проблему. На моей основной форме с ниже кода я don'g получают Событие mouseWheel:

public Form1()
    {
        InitializeComponent();

        this.panel1.MouseWheel += new MouseEventHandler(panel1_MouseWheel);
        this.panel1.MouseMove += new MouseEventHandler(panel1_MouseWheel);    
    }

, Но я действительно получаю событие с:

public Form1()
    {
        InitializeComponent();
        this.MouseWheel += new MouseEventHandler(panel1_MouseWheel);

    }

я надеюсь, что это более ясно без беспорядка Form2. Я просто пытаюсь получить События mouseWheel на Панели в моей основной форме.

С наилучшими пожеланиями,

James

15
задан mdb 14 October 2009 в 12:15
поделиться

2 ответа

На самом деле ваш сценарий не очень сильно соответствует блокировке - но мы все равно попробуем ;-p

Я немного изменил настройку; вместо:

  • одна организация может иметь территорию одновременно
  • когда команда финиширует, они сообщают первому, кого увидят (если кто-то ждет)
  • , когда уборщик заканчивает, они шумят - так все замечает, что они уходят, и пытается выйти на поле.

Вот код; обратите внимание, что у них нет блокировки, когда использует основание, так как это помешает другим людям присоединиться к очереди для Pulse .

В действительности, мы могли бы сделать ] все из этого с только блокировка (без использования Pulse ) и просто используйте стандартное поведение блокировки. Но этот пример показывает, что Pulse и PulseAll используются для повторной активации потоков при выполнении условия.

using System;
using System.Threading;
interface IGroundUser
{
    bool Invoke(); // do your stuff; return true to wake up *everyone*
                   // afterwards, else false
}
class Team : IGroundUser
{
    private readonly string name;
    public Team(string name) { this.name = name; }
    public override string ToString() { return name; }
    public bool Invoke()
    {
        Console.WriteLine(name + ": playing...");
        Thread.Sleep(25 * 250);
        Console.WriteLine(name + ": leaving...");
        return false;
    }
}
class Cleaner : IGroundUser
{
    public override string ToString() {return "cleaner";}
    public bool Invoke()
    {
        Console.WriteLine("cleaning in progress");
        Thread.Sleep(10 * 250);
        Console.WriteLine("cleaning complete");
        return true;
    }
}
class FootBallGround
{
    static void Main()
    {
        var ground = new FootBallGround();
        ThreadPool.QueueUserWorkItem(delegate { ground.UseGrounds(new Team("Team A")); });
        ThreadPool.QueueUserWorkItem(delegate { ground.UseGrounds(new Team("Team B")); });
        ThreadPool.QueueUserWorkItem(delegate { ground.UseGrounds(new Cleaner()); });
        ThreadPool.QueueUserWorkItem(delegate { ground.UseGrounds(new Team("Team C")); });
        ThreadPool.QueueUserWorkItem(delegate { ground.UseGrounds(new Team("Team D")); });
        ThreadPool.QueueUserWorkItem(delegate { ground.UseGrounds(new Team("Team E")); });
        Console.ReadLine();

    }
    bool busy;
    private readonly object syncLock = new object();
    public void UseGrounds(IGroundUser newUser)
    {
        // validate outside of lock
        if (newUser == null) throw new ArgumentNullException("newUser");
        // only need the lock when **changing** state
        lock (syncLock)
        {
            while (busy)
            {
                Console.WriteLine(newUser + ": grounds are busy; waiting...");
                Monitor.Wait(syncLock);
                Console.WriteLine(newUser + ": got nudged");
            }
            busy = true; // we've got it!
        }
        // do this outside the lock, allowing other users to queue
        // waiting for it to be free
        bool wakeAll = newUser.Invoke();

        // exit the game
        lock (syncLock)
        {
            busy = false;
            // wake up somebody (or everyone with PulseAll)
            if (wakeAll) Monitor.PulseAll(syncLock);
            else Monitor.Pulse(syncLock);
        }
    }    
}    
13
ответ дан 1 December 2019 в 04:01
поделиться

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

Монитор и блокировка

Ключевое слово lock является удобной оболочкой для Класс монитора . Это означает, что lock (obj) совпадает с Monitor. Введите (obj) (хотя Монитор имеет дополнительную функцию таймаута по истечении определенного периода времени, если ему не удалось получить блокировку объекта).

Импульсные события и потоки

Когда ряд потоков ожидают блокировки некоторого ресурса, с помощью кода вы можете сигнализировать, когда поток-владелец завершает работу с ресурсом. Это известно как сигнализация или пульсирующая , и ее можно выполнить с помощью Monitor.Pulse , Monitor.PulseAll , ManualResetEvent.Set или даже AutoResetEvent.Set .

Пример футбола

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

 namespace ThreadingSimulation
 {

   // A Random Activity can be picked up from this enum by a team

    public enum RandomGroundStatus
    {
        Free,
        Allotted,
        Wet          
    }

 class FootBallGround
 {
     private Team _currentTeam;

     // Set the initial state to true so that the first thread that 
     // tries to get the lock will succeed
     private ManualResetEvent _groundsLock = new ManualResetEvent(true);

     public bool Playing(Team obj)
     {
       // Here the name of the team which is using the  ground will be printed
       // Once the time is reached to 25 minutes the active thread the lock will
       // signal other threads    
       if (!_groundsLock.WaitOne(10))
         return false;

       _currentTeam = obj;

       // Reset the event handle so that no other thread can come into this method
       _groundsLock.Reset();    

       // Now we start a separate thread to "timeout" this team's lock 
       // on the football grounds after 25 minutes
       ThreadPool.QueueUserWorkItem(WaitForTimeout(25));                  
     }

    public void GroundCleaningInProgress(object obj)
    {

       // Ground cleaning is in progress all of you wait for 10 minutes

    }

    private void WaitForTimeout(object state)
    {
         int timeout = (int)state;

         // convert the number we specified into a value equivalent in minutes
         int milliseconds = timeout * 1000;
         int minutes = milliseconds * 60;

         // wait for the timeout specified 
         Thread.Sleep(minutes);

         // now we can set the lock so another team can play
         _groundsLock.Set();
     }
 }    

 class Team
  {
      string teamName;  
      FootBallGround _ground;

       public Team(string teamName, FootBallGround ground)
       {
          this.teamName = teamName;
          this._ground = ground;      
       }

       public bool PlayGame()
       {
            // this method returns true if the team has acquired the lock to the grounds
            // otherwise it returns false and allows other teams to access the grounds
            if (!_ground.Playing(this))
               return false;
            else
               return true;
       }
  }


  static void Main()
  {
         Team teamA = new Team();
         Team teamB = new Team();

         // select random value for GrandStatus from enum
         RandomGroundStatus status = <Generate_Random_Status>;

         // if the ground is wet no team is allowed to get the
         // ground for 10 minutes.
         if (status == RandomGroundStatus.Wet)
            ThreadPool.QueueUserWorkItem(WaitForDryGround);
         else
         {
             // if the ground is free, "Team A" locks the ground
             // otherwise "Team B" locks the ground

             if (status == RandomGroundStatus.Free)
             {
               if (!teamA.PlayGame())
                  teamB.PlayGame();
             }
          }
    }

}

** Примечания **

  • Используйте ManualResetEvent вместо lock и Monitor , поскольку нам нужен прямой контроль над , когда состояние блокировки является импульсным, чтобы другие потоки могли играть в футбол.

  • Передайте ссылку на FootBallGrounds каждой команде , потому что каждая команда будет играть на определенных площадках для игры в мяч, и каждое футбольное поле может быть занято другой командой

  • Пропуск со ссылкой на текущую команду, играющую на FootBallGround , потому что только одна команда может играть на площадке одновременно .

  • Используйте ThreadPool.QueueUserWorkItem , поскольку он более эффективен при создании простых потоков, чем создание потоков вручную. В идеале мы могли бы также использовать экземпляр Timer .

5
ответ дан 1 December 2019 в 04:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: