2009-09-26 19 views
5

मैं मैं क्या के लिए पूछ रहा हूँ करने के लिए अगले कोड उपयोग कर रहा हूँ:बटन दबाए जाने पर थ्रेड कैसे शुरू करें और फिर दबाए जाने पर इसे रोकें?

if (currBusyThrd != null && currBusyThrd.IsAlive) 
    { 
    currBusyThrd.Abort(); 
    } 
ThreadPool.SetMaxThreads(1, 1); 
//queue the work for thread processing 
ThreadPool.QueueUserWorkItem(new WaitCallback(WaitCallbackMethod)) 

"WaitCallbackMethod" विधि है::

void WaitCallbackMethod(object stateInfo) 
    { 
    // argList : i put some argument in a list to use it in "MethodToCall" ... 
    BeginInvoke(caler,argList); 
    } 

private delegate void CallerDelegate(object e); 
CallerDelegate caler = new CallerDelegate(MethodToCall); 
बटन क्लिक करें घटना पर

और जिस विधि को मैं थ्रेड द्वारा कॉल कर रहा हूं वह है:

void MethodToCall(object args) 
{ 
//Here I get the thread I'm calling to stop it when btn clicked again 
currBusyThrd = Thread.CurrentThread; 

// The rest of the code ... 
} 

मुझे लगता है कि यह गलत है ... यह कैसे सही है?

वास्तव में कॉलिंग TextBox_KeyUp द्वारा होगी .. इसलिए जब भी उपयोगकर्ता एक char दर्ज करता है तो कोड फिर से निष्पादित होगा .. और BackgroundWorker काम नहीं करता है।

+0

तो तुम शुरू करने और हर दूसरे कीस्ट्रोक के साथ एक लंबे समय से चल धागा रोक रहे हैं? –

+0

हाँ, बिल्कुल, मैं – Dabbas

+0

@ Al0NE करने की कोशिश कर रहा हूं, मैंने अपना जवाब अपडेट कर दिया है। ExecuteThreadLogicCondically() विधि देखें। –

उत्तर

9

इस दृष्टिकोण में एक समस्या यह है कि यह बहुत मनमाने ढंग से खतरे को छोड़कर खतरनाक है (किसी भी भाषा में)। ऐसे कई मुद्दे हैं जो अनचाहे संसाधनों और दुर्व्यवहार ताले के आसपास पॉपअप कर सकते हैं। थ्रेड को सुरक्षित रूप से निरस्त करने या थ्रेड के बारे में भूलने और इसे पूरा होने के लिए चलाने के लिए पूछने के लिए किसी प्रकार का झंडा सेट करना आम तौर पर सबसे अच्छा होता है।

इसके अतिरिक्त, थ्रेडपूल में एक थ्रेड को छोड़ना बहुत खतरनाक है और मुझे विश्वास है कि समर्थित ऑपरेशन नहीं है। थ्रेडपूल में थ्रेड्स आपके स्वामित्व में नहीं हैं और उन्हें ठंडा करने से थ्रेडपूल के लिए गंभीर प्रभाव पड़ता है।

यहां समाधान है जो मैं लेता हूं।

private object m_lock = new object(); 
private bool m_isRunning = false; 
private bool m_isAbortRequested = false; 

public void OnButtonClick(object sender, EventArgs e) { 
    lock (m_lock) { 
    if (m_isRunning) { 
     m_isAbortRequested = true; 
    } else { 
     m_isAbortRequested = false; 
     m_isRunning = true; 
     ThreadPool.QueueUserWorkItem(BackgroundMethod); 
    } 
    } 
} 

private void BackgroundMethod() { 
    try { 
    DoRealWork(); 
    } finally { 
    lock (m_lock) { 
     m_isRunning = false; 
    } 
    } 
} 

private void DoRealWork() { 
    ... 
    if (m_isAbortRequested) { 
    return; 
    } 
} 
+0

मैं काम करने वाले थ्रेड को रोकना चाहता हूं क्योंकि यह लंबे समय तक काम करता है और जब भी उपयोगकर्ता बीटीएन को मारता है तो यह करेगा। – Dabbas

+1

@ Al0NE: लगता है जैसे आप थ्रेड को काम करना चाहते हैं, जबकि थ्रेड समानांतर में नौकरी को पुनरारंभ करने से रोकने के लिए अपना काम कर रहा है? –

+1

@JaredPar, m_isAbortRequested ध्वज को किसी भी तरह अस्थिर या सिंक्रनाइज़ करने की आवश्यकता नहीं है क्योंकि यह UI थ्रेड द्वारा सेट किया गया है और थ्रेडपूल थ्रेड द्वारा चेक किया गया है? –

3

हाँ, यह बहुत गलत है। आपको कभी भी ThreadPool धागे को मैन्युअल रूप से नियंत्रित करने का प्रयास नहीं करना चाहिए। अगर आपको इस तरह के नियंत्रण की आवश्यकता है, तो आपको अपने Thread ऑब्जेक्ट का उपयोग करना चाहिए। इसके अलावा, Abort() धागे को समाप्त करने का अनुशंसित तरीका नहीं है; आपके पास अपने फॉर्म पर volatile bool पर नियंत्रण होना चाहिए कि MethodToCall में कोड विभिन्न बिंदुओं पर जांच करता है और true पर शानदार रूप से बाहर निकलता है। जबकि आप ThreadPool के साथ एक ही दृष्टिकोण का उपयोग कर सकते हैं, तो तथ्य यह है कि आपको रद्द करने में सक्षम होने की आवश्यकता है यह इंगित करता है कि प्रक्रिया लंबी चल रही है, या कम से कम होने की संभावना है। लंबे समय से चलने वाली प्रक्रियाओं के लिए ThreadPool का उपयोग नहीं किया जाना चाहिए।

उदाहरण के लिए ...

private volatile bool stopThread = false; 
private Thread workThread; 

private void StartThread() 
{ 
    if(workThread == null) 
    { 
     stopThread = false; 
     workThread = new Thread(new ThreadStart(MethodToCall)); 

     workThread.Start(); 
    } 
} 

private void StopThread() 
{ 
    if(workThread != null) 
    { 
     stopThread = true; 

     workThread.Join(); // This makes the code here pause until the Thread exits. 

     workThread = null; 
    } 
} 

फिर MethodToCall में, बस लगातार अंतराल पर stopThread बूलियन की जाँच करें और किसी भी सफाई का काम है कि आप क्या करना है और विधि से बाहर निकलने की जरूरत है। उदाहरण के लिए ...

private void MethodToCall() 
{ 
    // do some work here and get to a logical stopping point 

    if(stopThread) 
    { 
     // clean up your work 

     return; 
    } 

    // do some more work and get to another stopping point 

    if(stopThread) 
    { 
     // clean up your work 

     return; 
    } 
} 

और बस उस पैटर्न को दोहराएं।

2

स्थितियों के लिए जहां एक धागा करने के लिए 'सिग्नल' कुछ करने के लिए एक और धागा की जरूरत है, मैं आमतौर पर द्वितीय थ्रेड का संकेत देने वाला System.Threading.ManualResetEvent का उपयोग बंद करने के लिए, इस तरह:

private volatile bool _threadRunning = false; 
private ManualResetEvent _signal = new ManualResetEvent(false); 
private Thread _thread; 
private void OnButtonClick(object sender, EventArgs e) 
{ 
    if (!_threadRunning) { 
     // Reset the 'signal' event. 
     _signal.Reset(); 
     // Build your thread parameter here. 
     object param = ; 
     // Create the thread. 
     _thread = new Thread(ExecuteThreadLogicConditionally(param)); 
     // Make sure the thread shuts down automatically when UI closes 
     _thread.IsBackground = true; 
     // Start the thread. 
     _thread.Start(); 
     // Prevent another thread from being started. 
     _threadRunning = true; 
    } else { 
     // Signal the thread to stop. 
     _signal.Set(); 
     // DO NOT JOIN THE THREAD HERE! If the thread takes a while 
     // to exit, then your UI will be frozen until it does. Just 
     // set the signal and move on. 
    } 
} 
// If the thread is intended to execute its logic over and over until 
// stopped, use this callback. 
private void ExecuteThreadLogicUntilStopped(object param) 
{ 
    // Use a while loop to prevent the thread from exiting too early. 
    while (!_signal.WaitOne(0)) { 
     // Put your thread logic here... 
    } 
    // Set the flag so anther thread can be started. 
    _threadRunning = false; 
} 
// If the thread logic is to be executed once and then wait to be 
// shutdown, use this callback. 
private void ExecuteThreadLogicOnce(object param) 
{ 
    // Put your thread logic here... 
    // 
    // Now wait for signal to stop. 
    _signal.WaitOne(); 
    // Set the flag so another thread can be started. 
    _threadRunning = false; 
} 
// If the thread needs to be stopped at any point along the way, use 
// this callback. The key here is to 'sprinkle' checks of the 'signal' 
// to see if the thread should stop prematurely. 
private void ExecuteThreadLogicConditionally(object param) 
{ 
    if (_signal.WaitOne(0)) { _threadRunning = false; return; } 
    // Execute small chunk of logic here... 
    if (_signal.WaitOne(0)) { _threadRunning = false; return; } 
    // Execute another small chuck of logic here... 
    if (_signal.WaitOne(0)) { _threadRunning = false; return; } 
    // Continue this pattern through the method. 
} 

नोट यह है कि समाधान थ्रेडपूल का बिल्कुल उपयोग नहीं करता है। ऐसा करने के लिए आसानी से किया जा सकता है।और एक सुझाव के रूप में, मैं ThreadPool पर SetMaxThreads() फ़ंक्शन के साथ muck नहीं होगा। बस ThreadPool अपनी बात करते हैं। इसे आपके द्वारा उपयोग किए जाने के तरीके के लिए इष्टतम होने के लिए डिज़ाइन किया गया है।

+0

thanx, लेकिन अधिकांश समाधान "जबकि (NotAskingToStopTheThread)" का उपयोग करते हैं, लेकिन मेरे प्रश्न में मैंने यह उल्लेख किया है कि मैं नहीं चाहता कि थ्रेड अपने कार्य को पूरा कर सके .. मैं इसे इससे पहले रोकना चाहता हूं ... और जब उपयोग करते समय मैं ऐसा नहीं कर सकता – Dabbas

+0

जो कुछ आप पूछ रहे हैं वह करने का एकमात्र तरीका है कि थ्रेड को रोकना चाहिए या नहीं, यह देखने के लिए कि मेरे उदाहरण में मैन्युअल रीसेट, मेरे उदाहरण में मैन्युअल रीसेट करें। दूसरे शब्दों में, आपको अपने थ्रेड द्वारा निष्पादित कोड में तार्किक बिंदुओं पर इन चेकों को 'छिड़काव' करने की आवश्यकता है। मैं एक उदाहरण दिखाने के लिए अपना जवाब अपडेट करूंगा। आपकी सहायता के लिए –

+0

thanx @Matt – Dabbas

1

इस कोड का प्रयास करें ..

using System; 
using System.Linq; 
using System.Windows.Forms; 
using System.Threading; 
using System.Diagnostics; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     Thread workerThread = null; 
     ManualResetEvent threadInterrupt = new ManualResetEvent(false); 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      if (this.workerThread == null) 
      { 
       this.threadInterrupt.Reset(); 
       this.workerThread = new Thread(() => 
       { 
        int i = 0; 
        while (!this.threadInterrupt.WaitOne(0)) 
        { 
         Debug.Print("put your code in here while worker thread running.. " + i.ToString()); 
         Thread.Sleep(100); 
         i++; 
        } 
        this.workerThread = null; 
        // worker thread finished in here.. 
       }); 
       this.workerThread.IsBackground = true; 
       // start worker thread in here 
       this.workerThread.Start(); 
      } 
      else 
      { 
       // stop worker thread in here 
       threadInterrupt.Set(); 
      } 
     } 

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