थ्रेडस्टार्ट विधि में थ्रेड में पैरामीटर कैसे पास करें?


291

Thread.ThreadStart()सी # में विधि के लिए पैरामीटर कैसे पास करें ?

मान लीजिए, मेरे पास 'डाउनलोड' नामक विधि है

public void download(string filename)
{
    // download code
}

अब मैंने मुख्य विधि में एक धागा बनाया है:

Thread thread = new Thread(new ThreadStart(download(filename));

त्रुटि विधि प्रकार अपेक्षित।

मैं मापदंडों के ThreadStartसाथ लक्ष्य विधि के साथ पैरामीटर कैसे पारित कर सकता हूं ?


2
की जाँच करें इस लेख जॉन स्कीट पैरामीटर अनुभाग द्वारा लिखित अगले पन्ने पर है, लेकिन एक पूरे के रूप लेख एक बहुत अच्छा पढ़ा है।
कोडिंगबर्गर

जवाबों:


696

सबसे सरल है

string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();

इस (अधिक ParameterizedThreadStart) का लाभ यह है कि आप कई मापदंडों को पारित कर सकते हैं, और आपको objectहर समय कास्ट करने की आवश्यकता के बिना संकलन-समय की जाँच मिलती है ।


15
मैं ऑफॉप्टिक के लिए माफी चाहता हूं लेकिन '()' ऑपरेटर का क्या मतलब है? मैं इसे कभी-कभी देखता हूं लेकिन मेरे पास जांच का समय नहीं है।
atukaszW.pl

24
यह बिना किसी तर्क के एक लंबोदर अभिव्यक्ति है।
नोल्डोरिन

31
@ ŁukaszW.pl - क्या Noldorin कहा, सी में पी # 2.0 एक विकल्प के निर्माण (इस उदाहरण के लिए) हैnew Thread(delegate() { download(filename); });
मार्क Gravell

7
@ टायमेक काफी सटीक नहीं है ; कैप्चर किए गए किसी भी वैरिएबल को पूर्ण लेक्सिकल क्लोजर के रूप में माना जाता है , जो (एक कार्यान्वयन विस्तार के रूप में) एक कंपाइलर-जनरेटेड क्लास पर फ़ील्ड के रूप में लागू किया जाता है। इसके अतिरिक्त, क्लोजर स्कोप को डिक्लेरेशन स्कोप के रूप में परिभाषित किया जाता है। यह "संदर्भ के रूप में" इस तरह के रूप वास्तव में नहीं है ( "संदर्भ से गुजरती हैं" और "संदर्भ प्रकार" दोनों अच्छी तरह से परिभाषित कर रहे हैं, और न तो वास्तव में इस परिदृश्य का वर्णन)
मार्क Gravell

5
@MarcGravell - आप सही हैं। मुझे केवल इतना कहना चाहिए कि किसी को पता होना चाहिए कि यदि थ्रेड शुरू होने से पहले 'फ़ाइल नाम' बदल जाता है तो नए मूल्य का उपयोग किया जाएगा। मुझे इसके बारे में यांत्रिकी के बारे में नहीं सोचना चाहिए था और मुझे निश्चित रूप से संदर्भित करने के बारे में बात नहीं करनी चाहिए थी।
tymtam

37

इस उदाहरण को देखें:

public void RunWorker()
{
    Thread newThread = new Thread(WorkerMethod);
    newThread.Start(new Parameter());
}

public void WorkerMethod(object parameterObj)
{
    var parameter = (Parameter)parameterObj;
    // do your job!
}

आप पहले डेलिगेट को वर्कर मेथड में पास करके एक थ्रेड बना रहे हैं और फिर इसे थ्रेड से शुरू करते हैं। यह मेथड है जो आपके ऑब्जेक्ट को पैरामीटर के रूप में लेता है।

तो आपके मामले में आपको इसे इस तरह से उपयोग करना चाहिए:

    Thread thread = new Thread(download);
    thread.Start(filename);

लेकिन आपकी 'डाउनलोड' पद्धति को अभी भी ऑब्जेक्ट लेने की ज़रूरत है , न कि एक पैरामीटर के रूप में स्ट्रिंग । आप इसे अपने विधि निकाय में स्ट्रिंग करने के लिए डाल सकते हैं।


25

आप ParameterizedThreadStartपैरामीटर लेने वाले थ्रेड विधियों के लिए प्रतिनिधि का उपयोग करना चाहते हैं । (या वास्तव में कोई नहीं, और Threadनिर्माणकर्ता को अनुमान लगाने दें।)

उदाहरण का उपयोग:

var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent

thread.Start(filename)

7

आप भी delegateऐसा कर सकते हैं ...

ThreadStart ts = delegate
{
      bool moreWork = DoWork("param1", "param2", "param3");
      if (moreWork) 
      {
          DoMoreWork("param1", "param2");
      }
};
new Thread(ts).Start();


3

आप थ्रेड फ़ंक्शन (डाउनलोड) और आवश्यक पैरामीटर (एस) (फ़ाइल नाम) को एक कक्षा में इनकैप्सुलेट कर सकते हैं और थ्रेडस्टार्ट प्रतिनिधि का उपयोग करके थ्रेड फ़ंक्शन को निष्पादित कर सकते हैं।

public class Download
{
    string _filename;

    Download(string filename)
    {
       _filename = filename;
    }

    public void download(string filename)
    {
       //download code
    }
}

Download = new Download(filename);
Thread thread = new Thread(new ThreadStart(Download.download);

मुझे यह दृष्टिकोण बहुत अच्छा लगता है, मैंने पाया कि
लंबोदर

3

मैं आपको फाइल नामक एक अन्य वर्ग रखने की सलाह दूंगा।

public class File
{
   private string filename;

   public File(string filename)
   {
      this.filename= filename;
   }

   public void download()
   {
       // download code using filename
   }
}

और आपके थ्रेड क्रिएशन कोड में, आप एक नई फ़ाइल को इंस्टेंट करते हैं:

string filename = "my_file_name";

myFile = new File(filename);

ThreadStart threadDelegate = new ThreadStart(myFile.download);

Thread newThread = new Thread(threadDelegate);

0

इस बारे में कैसे: (या इस तरह का उपयोग करना ठीक है?)

var test = "Hello";
new Thread(new ThreadStart(() =>
{
    try
    {
        //Staff to do
        Console.WriteLine(test);
    }
    catch (Exception ex)
    {
        throw;
    }
})).Start();

-1

आपके प्रश्न के अनुसार ...

थ्रेड से ट्रेड.आर्टस्टार्ट () विधि को C # में कैसे पास करें?

... और आपके द्वारा की गई त्रुटि, आपको अपना कोड सही करना होगा

Thread thread = new Thread(new ThreadStart(download(filename));

सेवा

Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);



हालांकि, यह सवाल अधिक जटिल है क्योंकि यह पहले लगता है।

Threadवर्ग वर्तमान में (4.7.2) कई प्रदान करता है कंस्ट्रक्टर्स और एक Startभार के साथ विधि।

इस प्रश्न के लिए ये प्रासंगिक निर्माता हैं:

public Thread(ThreadStart start);

तथा

public Thread(ParameterizedThreadStart start);

जो या तो एक ThreadStartप्रतिनिधि या एक ParameterizedThreadStartप्रतिनिधि लेते हैं ।

संबंधित प्रतिनिधि इस तरह दिखते हैं:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

जैसा कि देखा जा सकता है, उपयोग करने के लिए सही कंस्ट्रक्टर एक ParameterizedThreadStartप्रतिनिधि लेने वाला प्रतीत होता है ताकि प्रतिनिधि द्वारा निर्दिष्ट हस्ताक्षर के अनुरूप कुछ विधि शुरू की जा सके।

Threadवर्ग को अस्थिर करने के लिए एक सरल उदाहरण होगा

Thread thread = new Thread(new ParameterizedThreadStart(Work));

या केवल

Thread thread = new Thread(Work);

संबंधित विधि का हस्ताक्षर ( Workइस उदाहरण में कहा जाता है) इस तरह दिखता है:

private void Work(object data)
{
   ...
}

जो कुछ बचा है वह धागा शुरू करना है। यह या तो उपयोग करके किया जाता है

public void Start();

या

public void Start(object parameter);

जबकि Start()थ्रेड प्रारंभ होगा और nullविधि के डेटा के रूप में पास होगा, थ्रेड की विधि में कुछ भीStart(...) पारित करने के लिए इस्तेमाल किया जा सकता है ।Work

हालांकि इस दृष्टिकोण के साथ एक बड़ी समस्या है: Workविधि में पारित सब कुछ एक वस्तु में डाली जाती है। इसका मतलब है कि Workविधि के भीतर इसे मूल प्रकार में फिर से डालना होगा जैसे कि निम्नलिखित उदाहरण में:

public static void Main(string[] args)
{
    Thread thread = new Thread(Work);

    thread.Start("I've got some text");
    Console.ReadLine();
}

private static void Work(object data)
{
    string message = (string)data; // Wow, this is ugly

    Console.WriteLine($"I, the thread write: {message}");
}



कास्टिंग कुछ ऐसा है जो आप आमतौर पर नहीं करना चाहते हैं।

क्या होगा अगर कोई कुछ और गुजरता है जो एक स्ट्रिंग नहीं है? जैसा कि यह पहली बार में संभव नहीं लगता है (क्योंकि यह मेरी विधि है, मुझे पता है कि मैं क्या करता हूं या विधि निजी है, किसी को कभी भी इसे कैसे पारित करने में सक्षम होना चाहिए? ) संभवतः आप विभिन्न कारणों से वास्तव में उस मामले को समाप्त कर सकते हैं ? । जैसा कि कुछ मामलों में समस्या नहीं हो सकती है, अन्य हैं। ऐसे मामलों में आप शायद समाप्त हो जाएंगे, InvalidCastExceptionजिसे आप शायद नोटिस नहीं करेंगे क्योंकि यह केवल धागे को समाप्त करता है।

एक समाधान के रूप में आप एक सामान्य ParameterizedThreadStartप्रतिनिधि प्राप्त करने की उम्मीद करेंगे जैसे ParameterizedThreadStart<T>कि Tडेटा का प्रकार आप Workविधि में पारित करना चाहते हैं । दुर्भाग्य से ऐसा कुछ मौजूद नहीं है (अभी तक?)।

हालाँकि इस समस्या का एक हल है। इसमें एक वर्ग बनाना शामिल है जिसमें दोनों शामिल हैं, थ्रेड को पास करने के लिए डेटा और साथ ही वह विधि जो इस तरह से कार्यकर्ता पद्धति का प्रतिनिधित्व करती है:

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

इस दृष्टिकोण के साथ आप इस तरह धागा शुरू करेंगे:

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

तो इस तरह से आप बस कास्टिंग करने से बचते हैं और एक थ्रेड को डेटा प्रदान करने का एक प्रकार है; ;;;


-2

यहाँ सही तरीका है ...

private void func_trd(String sender)
{

    try
    {
        imgh.LoadImages_R_Randomiz(this, "01", groupBox, randomizerB.Value); // normal code

        ThreadStart ts = delegate
        {
            ExecuteInForeground(sender);
        };

        Thread nt = new Thread(ts);
        nt.IsBackground = true;

        nt.Start();

    }
    catch (Exception)
    {

    }
}

private void ExecuteInForeground(string name)
{
     //whatever ur function
    MessageBox.Show(name);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.