2015-07-22 25 views
7

Bir Görevlinin bir Zamanlayıcı tarafından neden iyi işlediğini, ancak bir Görev tarafından bir Zamanlayıcı'nın neden ortaya çıktığını açık bir şekilde açıklayamam.Timer Spawn Göreve Göre Görev ve Görev Spawn By Timer

İlgili tüm kodlar aşağıda yer almaktadır, böylece kolayca yeniden üretebilirsiniz.

Form.cs:

private void Form1_Load(object sender, EventArgs e) 
{ 
    ProcessDelayList list = new ProcessDelayList(); 

    foreach (ProcessDelay p in list) 
    { 
     //this works 
     p.Start(); 

     //this does NOT work 
     //Task.Factory.StartNew(() => p.Start()); 
    } 
} 

ProcessDelayList.cs:

public class ProcessDelayList : List<ProcessDelay> 
{ 
    public ProcessDelayList() 
    { 
     Add(new ProcessDelay("Process 1", 2000)); 
     Add(new ProcessDelay("Process 2", 4000)); 
     Add(new ProcessDelay("Process 3", 6000)); 
     Add(new ProcessDelay("Process 4", 8000)); 
     Add(new ProcessDelay("Process 5", 10000)); 
    } 
} 

ProcessDelay.cs:

public class ProcessDelay 
{ 
    private string name; 
    private int delay; 
    private Timer timer; 

    public ProcessDelay(string name, int delay) 
    { 
     this.name = name; 
     this.delay = delay; 
    } 
    public void Start() 
    { 
     timer = new Timer(); 
     timer.Interval = delay; 
     timer.Tick += timer_Tick; 
     timer.Start(); 
    } 
    private void timer_Tick(object sender, EventArgs e) 
    { 
     //these work either way, as long as the task 
     // is NOT spawn in the main loop. 

     //TimerProc(); 
     TimerProcTask(); 
    } 
    private void TimerProcTask() 
    { 
     Task.Factory.StartNew(() => TimerProc()); 
    } 
    private void TimerProc() 
    { 
     timer.Stop(); 
     MessageBox.Show(name, delay.ToString()); 
    } 
} 
+0

Yeni Görev'i kullanmaya çalışabilir misiniz (() => p.Start()) Start() ;? – thinklarge

+0

@thinklarge: InvalidOperationException: Başlangıç, başlatılmış olan bir görevde çağrılmayabilir. – jsanalytics

cevap

8

Ah zamanlayıcılar. .NET'te, her biri biraz farklı davranışlarla dördü vardır. System.Windows.Forms.Timer kullanıyorsunuz.

Bu zamanlayıcı, zamanlayıcı olaylarını (WM_TIMER) tetiklemek için Win32 ileti kuyruğunu kullanır. Zamanlayıcıyı oluşturan iş parçacığı, geri çağrı yönteminin (timer_Tick) yürütüldüğü düzendir. Zamanlayıcının yürütülmesi için iş parçacığının bir mesaj pompaya ihtiyacı vardır. Geçerli SynchronizationContext çalışmak üzere görevi söylemek

o iş yapacak:

Task.Factory.StartNew(() => p.Start(), 
       CancellationToken.None, 
       TaskCreationOptions.LongRunning, 
       TaskScheduler.FromCurrentSynchronizationContext()); 

Bu aslında olsa UI iş parçacığı üzerinde gerçekleşmesi çağrısını sýralar, bu nedenle tüm eğer, bana tür anlamsız görünüyor Yapıyorsunuz zaten p.Start() yöntemini çağırıyor (hemen hemen tek iş parçacıklı).

Not System.Windows.Forms.Timer sınıfının sözleri bölümü: Bu, Windows zamanlayıcı UI iş parçacığı işleme gerçekleştirmek için kullanılan tek iş parçacıklı ortam için tasarlanmıştır

. Kullanıcı kodunun bir UI mesaj pompasına sahip olmasını ve aynı iş parçacığından her zaman çalışmasını veya aramayı başka bir iş parçacığına yönlendirmesini gerektirir. Eğer zamanlayıcı aslında ayrı iş parçacığı üzerinde yürütmek için çağırır istiyorsanız

Sen System.Threading.Timer kullanmak (ya da bu sınıfın System.Timers.Timer sarıcı) olabilir. Kullanıcı Arabirimini güncellemek için zamanlayıcı geri aramanıza gerek duyarsanız, UI iş parçacığına UI iş parçacığı güncelleştirmesini güncelleştirmeniz gerekir. Ancak, yoğun işlem gerektiren herhangi bir işin ayrı bir iş parçacığı üzerinde yapıldığından emin olabilirsiniz ve yalnızca en küçük miktarda kod (örneğin denetimlerin gerçek güncelleştirmesi), UI iş parçacığına yanıt vermesini sağlamak için yapılır.