2015-07-22 11 views
7

मैं स्पष्ट रूप से स्पष्ट रूप से समझा नहीं सकता कि टाइमर द्वारा किए गए कार्य को ठीक क्यों काम करता है लेकिन कार्य द्वारा टाइमर स्पॉन नहीं होता है।टाइमर द्वारा कार्य और कार्य स्पॉन द्वारा टाइमर स्पॉन

सभी प्रासंगिक कोड नीचे शामिल हैं ताकि आप इसे आसानी से पुन: उत्पन्न कर सकें।

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

क्या आप नए कार्य (() => p.Start()) का उपयोग करने का प्रयास कर सकते हैं। प्रारंभ() ;? – thinklarge

+0

@thinklarge: InvalidOperationException: प्रारंभ से पहले से शुरू किए गए कार्य पर प्रारंभ नहीं किया जा सकता है। – jsanalytics

उत्तर

8

आह, टाइमर। उनमें से चार .NET में हैं, प्रत्येक में थोड़ा अलग व्यवहार हैं। आप System.Windows.Forms.Timer का उपयोग कर रहे हैं।

यह टाइमर टाइमर ईवेंट (WM_TIMER) को Win32 संदेश कतार का उपयोग करता है। टाइमर बनाता है जो थ्रेड वह है जिस पर कॉलबैक विधि (timer_Tick) निष्पादित की जाती है। टाइमर निष्पादित करने के लिए धागे को एक संदेश पंप की आवश्यकता होती है।

वर्तमान SynchronizationContext पर चलाने के लिए कार्य बोलने यह काम कर देगा:

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

यह वास्तव में कॉल हालांकि, यूआई धागा पर होने मार्शलों तो यह मेरे लिए एक तरह से व्यर्थ लगता है सब करता है, तो आप कर रहे हैं p.Start() विधि वैसे भी कॉल कर रहा है (बहुत अधिक एकल धागा काम करता है)।

नोट System.Windows.Forms.Timer वर्ग की टिप्पणी अनुभाग:

यह विंडोज टाइमर एक एकल पिरोया वातावरण जहां यूआई धागे प्रसंस्करण प्रदर्शन करने के लिए उपयोग किया जाता है के लिए बनाया गया है। यह आवश्यक है कि उपयोगकर्ता कोड में यूआई संदेश पंप उपलब्ध हो और हमेशा एक ही थ्रेड से संचालित हो, या किसी अन्य धागे पर कॉल को मार्शल करें।

आप (या इस वर्ग की System.Timers.Timer आवरण) System.Threading.Timer उपयोग कर सकते हैं अगर आप अपने टाइमर वास्तव में एक अलग थ्रेड पर अमल करने के लिए कहता है चाहता हूँ। यदि आपको UI को अपडेट करने के लिए अपने टाइमर कॉलबैक की आवश्यकता है, तो आपको UI थ्रेड पर यूआई अपडेट कॉल को मार्शल करना होगा। हालांकि, आप यह सुनिश्चित कर सकते हैं कि किसी भी प्रसंस्करण-गहन कार्य को अलग थ्रेड पर किया जाता है, और केवल उत्तर की छोटी मात्रा (जैसे नियंत्रणों का वास्तविक अद्यतन) इसे उत्तरदायी रखने के लिए UI थ्रेड पर किया जाता है।

संबंधित मुद्दे