2015-12-11 2 views
1

Я запускаю базовое однопоточное приложение.Как этот блокирующий поток вызывает «освобождение»?

Как правило, при вызове System.Windows.Forms.MessageBox.Show() можно было бы ожидать, что этот вызов эффективно блокирует дальнейшее выполнение до тех пор, пока этот метод не вернется.

Однако при использовании System.Windows.Forms.Timer, кажется * же * нить какая-то образом освобождаясь и Timer «s Tick события стрельбы по этой же теме.

Что происходит дальше? У меня такое чувство, что это может иметь какое-то отношение к нарезке квартир, но я хотел бы получить некоторые разъяснения.

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

class Program 
{ 
    static void Main(string[] args) 
    { 
     new Program(); 
     while (true) 
     { 
      System.Windows.Forms.Application.DoEvents(); 
     } 
    } 

    private System.Windows.Forms.Timer timer; 

    public Program() 
    { 
     timer = new System.Windows.Forms.Timer() { Interval = 2000 }; 
     timer.Tick += timer_Tick; 
     timer.Start(); 
    } 

    private void timer_Tick(object sender, EventArgs e) 
    { 
     Console.WriteLine(string.Format("Thread {0} has entered", Thread.CurrentThread.ManagedThreadId)); 
     var result = MessageBox.Show("Test"); 
     Console.WriteLine(string.Format("Thread {0} has left", Thread.CurrentThread.ManagedThreadId)); 
    } 
} 

Выход:

Thread 10 вступил
тему 10 вступил
тему 10 вступил
тему 10 введено
Резьба 10 введена

+1

Это не хорошая тестовая программа, потому что вызов 'Application.DoEvents()' даст именно такое поведение. Можете ли вы воспроизвести его с помощью простого приложения Windows Forms? –

+0

Я только называю это в моем коротком примере, так как это будет делать приложение winforms по умолчанию. – maxp

+1

Приложение winforms по умолчанию НЕ будет вызывать 'Application.DoEvents()' –

ответ

6

Когда отображается модальное окно, такое как окно сообщения, насос сообщений Windows продолжает работать.

Если бы этого не произошло, отображение окна позади модального окна не обновлялось при перемещении модального окна перед ним.

Поскольку сообщения Windows все еще перекачиваются, сообщения «WM_TIMER» по-прежнему будут отправляться в окно без переднего плана, и, следовательно, вы увидите поведение, которое вы отметили.

Главное, что следует отметить, что таймер Windows заставляет Windows отправлять сообщения «WM_TIMER» в очередь событий окна, и пока работает насос сообщений окна, события таймера будут продолжать обрабатываться.

Одним из распространенных способов избежать этой проблемы с повторным входом является отключение таймера при обращении с тиком.

Например, поставить галочку на обработку кода в метод, называемый handleTimer(), а затем обрабатывать клеща так:

private void timer_Tick(object sender, EventArgs e) 
{ 
    timer.Enabled = false; 

    try 
    { 
     handleTimer(); 
    } 

    finally 
    { 
     timer.Enabled = true; 
    } 
} 

(Вы могли бы хотеть не повторно включить таймер в случае исключения, в этом случае вам не понадобится следующая логика try/finally.)

+0

Существует не такая вещь, как блокировка «одного потока», так есть ли способ блокировать такое повторение, кроме как вручную, используя «bool» для блокировки вручную? – maxp

+1

@maxp Я обычно делаю это, чтобы вызвать 'timer.Enabled = false;' как самую первую вещь в обработчике, а затем 'timer.Enabled = true;' как самую последнюю вещь. Я добавлю это к моему ответу. –

Смежные вопросы