2013-05-13 19 views
8

रॉब माइल्स (here) से बहुत अच्छा पीडीएफ पढ़ने के दौरान मैं हाल ही में थ्रेड में जा रहा हूं। उनके पास पृष्ठ 160 (2012, सी # पीडीएफ) पर एक उदाहरण था, लेकिन यह कंसोल को नहीं लिखा था बस खाली लूप किया था।जब मैं कंसोल पर चीजों को मुद्रित करने के लिए थ्रेड का उपयोग करता हूं, तो यह अजीब परिणाम क्यों उत्पन्न करता है?

मैंने एक बहुत ही सरल धागा उत्पादन लूप लिखा जो 10 धागे बनाता है जो 1000 के प्रत्येक बहुमत पर स्क्रीन पर अपनी आईडी लिख रहे हैं। यह अच्छा था - यह दिखाता है कि धागे एक साथ कैसे चल रहे थे। मेरे प्रश्न शुरू होते हैं मेरा आउटपुट इतनी उलझन में क्यों है? अक्सर जब मैं नीचे प्रोग्राम चलाता हूं, तो मुझे कई "थ्रेड 3 समाप्त" लाइनें मिलती हैं जहां मैं बहुत निश्चित हूं, मुझे केवल प्रत्येक में से एक होना चाहिए।

मैंने एमएसडीएन से लूप तक "lock" जोड़ा लेकिन यह अभी भी अजीब आउटपुट उत्पन्न करता है (मैं नीचे एक उदाहरण डालूंगा)।

namespace ConsoleApplication1 
    { 
     class Program 
     { 
      static object sync = new object(); 

      static void Main(string[] args) 
      { 
       for (int i = 0; i < 10; i++) 
       { 
        Thread myThread = new Thread(() => DoThis(i)); 
        myThread.Start(); 
       } 
       Console.ReadLine(); 
      } 

      static void DoThis(int s) 
      { 
       lock (sync) // a new addition that hasn't helped 
       { 
        for (long j = 0; j < 10000; j++) 
        { 
         if (j % 1000 == 0) Console.Write(String.Format("{0}.", s)); 
        } 
        Console.WriteLine("\r\nThread {0} Finished", s); 
        Debug.Print("\r\nThread {0} Finished", s); //<-- added to debug 

       } 
      } 
     } 
    } 

मैंने सोचा कि मैं ठीक कर रहा था - मैं स्थानीय चर (मेरी गिनती पाश) है, मैं किसी पूर्णांक कि शायद संदर्भ द्वारा नहीं पारित हो जाता है और बाद में मैं थोड़ी देर कर रही है यह पाश है यह ताला करने की कोशिश की है। कोई खुशी नहीं। आउटपुट को समझदार बनाने के लिए मुझे क्या करना होगा? मैंने समस्या निवारण के लिए Deubg.Print की कोशिश की लेकिन इसमें त्रुटियां भी हैं (नीचे)।

आखिरकार, मैं बड़े आवेदन में थ्रेडिंग का उपयोग करना चाहता हूं लेकिन अगर मैं इसे यहां नहीं प्राप्त कर सकता, तो मुझे यकीन नहीं है कि मैं चाहता हूं! अंत में debug.print लाइन से

उदाहरण आउटपुट: (गुणकों ध्यान दें) ...

Thread 1 Done 
The thread '<No Name>' (0x15cc) has exited with code 0 (0x0). 

Thread 9 Done 
The thread '<No Name>' (0x1d0c) has exited with code 0 (0x0). 

Thread 6 Done 
The thread '<No Name>' (0x2248) has exited with code 0 (0x0). 

Thread 10 Done 
The thread '<No Name>' (0x22bc) has exited with code 0 (0x0). 

Thread 9 Done 
The thread '<No Name>' (0x85c) has exited with code 0 (0x0). 

Thread 9 Done 
The thread '<No Name>' (0x1628) has exited with code 0 (0x0). 

Thread 3 Done 
The thread '<No Name>' (0x2384) has exited with code 0 (0x0). 

Thread 6 Done 

Thread 2 Done 

Thread 4 Done 
The thread '<No Name>' (0x2348) has exited with code 0 (0x0). 
The thread '<No Name>' (0x2420) has exited with code 0 (0x0). 
The thread '<No Name>' (0x1ea8) has exited with code 0 (0x0). 

मुझे पता है कि अगर मैं मैं क्या है पर किसी भी अधिक जानकारी की पेशकश कर सकते हैं कोशिश की।

+1

मुझे लगता है कि लूप में आपका चर कैप्चर किया गया है। एक अस्थायी चर में स्टोर करें। लेकिन अगर आपका मतलब है कि आउटपुट का आदेश क्यों नहीं दिया जाता है .. थ्रेड के निष्पादन को शुरू करने के क्रम में होने की गारंटी नहीं है। –

+0

सटीक आदेश के बारे में चिंतित नहीं है लेकिन ऐसा लगता है कि @MatthewWatson ने उत्तर दिया है ... धन्यवाद। – Sisyphus

+0

[सी # कैप्चर वैरिएबल इन लूप] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop) – nawfal

उत्तर

10

आपकी समस्या यह है कि आप लूप चर पर "संशोधित बंद" का उपयोग कर रहे हैं।

इस हालांकि foreach छोरों के लिए तय किया गया है, for छोरों अभी भी समस्या आ रही है (और हमेशा होगा)

इसे ठीक करने के लिए, यह करने के लिए अपने मुख्य() बदलने के लिए: के लिए

static void Main(string[] args) 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     int copy = i; // Make a copy of i to prevent the "modified closure" problem. 
     Thread myThread = new Thread(() => DoThis(copy)); 
     myThread.Start(); 
    } 
    Console.ReadLine(); 
} 

देखें यहां अधिक जानकारी के:

Access to Modified Closure

Eric Lippert's Article on Closures

+0

+1 निश्चित रूप से मानते हुए ओपी 'नेट 4.5' का उपयोग नहीं करता है। – I4V

+0

ठीक है, मैं उस "मैं" पर संदिग्ध रूप से देख रहा था ... मुझे एक त्वरित खेलना है। – Sisyphus

+2

@ IV4 बंद करने की चीज़ 'फॉरच' लूप के लिए 'फॉर लूप' के लिए नहीं बदली है। Http://stackoverflow.com/questions/16264289/captured-closure-loop-variable-in-c-sharp-5-0 –

5

Parallel.For के बजाय अपने आप को एक पाश में उपयोग करते हुए शुरू करने धागे का प्रयास करें:

Parallel.For(0, 10, DoThis); 

अगर आपको लगता है कि के हिस्से के रूप में एक अतिरिक्त तर्क (जैसे कि w) पारित करने के लिए की जरूरत है, तो आप ऐसा कर सकते हैं:

var w = 4; 
Parallel.For(0, 10, i => DoThis(i, w)); 

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

इसके अलावा आपके lock (sync) किसी भी दो धागे को एक ही समय में अपने ऑपरेशन करने से रोकने जा रहा है।

ध्यान रखें कि आपके धागे किसी भी विशेष क्रम में निष्पादित करने की गारंटी नहीं देते हैं।

+0

मुझे वास्तव में कोई आदेश नहीं है - लॉक मुझे था यह पता लगाने की कोशिश कर रहा था कि क्या गलत हो रहा था! मैंने कभी समानांतर उपयोग नहीं किया है। (और कई, कई अन्य चीजें) तो एक त्वरित पढ़ा जाएगा। – Sisyphus

+0

क्या मैं अभी भी एक चर को दोथिस विधि में पास कर सकता हूं? – Sisyphus

+1

'समांतर। के लिए 'सूचकांक (0..9) को' डोथिस 'के पैरामीटर के रूप में पास करता है -' डोथिस 'प्रतिनिधि से मेल खाता है, इसकी उम्मीद है कि मैंने आपको जो कुछ दिया है उसे' बस काम करें ' – PhonicUK

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

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