2012-03-28 14 views
6

ठीक है..यह लंबा होगा लेकिन मुझे पहले कुछ पृष्ठभूमि की व्याख्या करने की आवश्यकता है।मल्टीथ्रेडिंग और सीरियल पोर्ट

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

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

मेरा कोड इसके लिए काम करेगा .. समस्या यह है कि यह कई वस्तुओं के लिए काम नहीं करेगा। इसका मतलब है, जबकि एक गेट खुला है, गेट बंद होने तक सेंसर की निगरानी नहीं की जा रही है। इसलिए जब आइटम ए गेट के रास्ते पर है, तो आइटम बी को सेंसर को अवरुद्ध करते समय स्केल पर वजन नहीं मिलेगा। मेरे पास लाइन पर 8 आइटम तक एक बार हो सकता है।

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
} 

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if sensor is blocked 
    if (sensorstatus == 0) 
    { 
     //the timers just start the thread 
     scaleTimer.Start(); 
    } 
    else 
    { 
     sensorTimer.Start(); 
    } 
} 

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     ReadScale(); 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     SetOpenDelay(); 
     SetDuration(); 
    } 
    } 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if gate = 0, this means the weight of meat on scale 
    //is not in any weight range. Meat runs off the end. 
    if (gate == 0) 
    { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
     sensorTimer.Start(); 
    } 
    else 
    { 
     //open gate 
     //then close gate 
    } 
    } 

इस कोड को ठीक काम करता है, मैं सिर्फ लाइन पर कई आइटम प्राप्त करने में सक्षम होने की जरूरत है: यहाँ कोड मैं अब चल रहा हूँ। कोई सुझाव ????

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
}  

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    sensorTimer.Start(); 
} 

    private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     //sensor blocked 
     if (sensorstatus == 0) 
     { 
      ReadScale(); 
      //SaveWeight(); 
      prevgate = gate; 
      gate = DetermineGate(); 
      SetOpenDelay(); 
      SetDuration(); 

      //if gate = 0, this means the weight of meat on scale 
      //is not in any weight range. Meat runs off the end. 
      if (gate == 0) 
      { 
      txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
      } 
      else 
      { 
      //open gate 
      //close gate 
      } 
    } 
} 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    scaleTimer.Start(); 
} 

जब मैं ऐसा किया, मैं दोनों धागे शुरू हुई जब शुरू बटन दबाया गया था:

मैं भी निम्नलिखित की कोशिश की है। मुझे सभी प्रकार के अपवाद मिलते हैं और कार्यक्रम अंततः SEHException और क्रैश फेंकता है। मुझे लगता है कि अन्य त्रुटियां "सीरियल पोर्ट पहले ही खोला गया है" या "I/O त्रुटि"।

+0

है हो रही है समस्या पता नहीं है, तो ताले की जरूरत है लेकिन मैं उन्हें सुरक्षा के लिए कहा कि DetermineGate(), SetOpenDelay() और SetDuration दौरान पैमाने धागा ब्लॉक()? मैं अभी तक आपका कोड पूरी तरह समझ नहीं रहा हूं। ऐसा लगता है कि यह अभी भी बहुत प्रक्रियात्मक है, भले ही आप धागे का उपयोग कर रहे हों - ऐसा लगता है कि धागे हमेशा एक दूसरे पर इंतजार कर रहे हैं। क्या यह हो रहा है? –

+0

एफवाईआई, यहां सी # में मल्टीथ्रेडिंग पर एक शानदार लिंक है: http://www.yoda.arachsys.com/csharp/threads/index.shtml –

+0

यह मेरी पहली बार मल्टीथ्रेडिंग है।मुझे इसकी आवश्यकता थी जहां मेरा जीयूआई लॉक नहीं होगा। मुझे यकीन नहीं है कि "थ्रेड स्केल ब्लॉक" से आपका क्या मतलब है धागे एक-दूसरे पर इंतजार कर रहे हैं .. लेकिन जब मैंने इसे ठीक करने का प्रयास किया, तो मुझे अभी त्रुटियों का एक गुच्छा मिला (मेरा संपादन देखें)। मुझे कन्वेयर बेल्ट चलाने में सक्षम होने के लिए इस सॉफ़्टवेयर की आवश्यकता है। यह सेंसर द्वारा गुजरने वाली वस्तुओं के लिए कहने की दर पर खाता होना चाहिए ... 1 आइटम प्रत्येक 3 सेकंड। इसलिए सभी द्वार खोलने/बंद होने चाहिए क्योंकि आइटम अपने द्वार पर आता है। मुझे पता है कि यह भ्रमित लगता है..क्या आप समझते हैं कि मैं क्या करने की कोशिश कर रहा हूं? लिंक – CSharpDev

उत्तर

1

मैं सुझाव दूंगा कि आपकी सर्वश्रेष्ठ शर्त शायद प्रत्येक धारावाहिक बंदरगाह पर बैठने के लिए समर्पित धागा तैयार करे। ऐसे दृष्टिकोण को न तो बंदरगाहों के संचालन में किसी भी तरह की समानता की आवश्यकता होगी, न ही मना कर दिया जाएगा, बंदरगाहों के बीच संचालन में हस्तक्षेप से बच जाएगा, और उचित सीमाओं के भीतर स्केलेबल होगा (32 बंदरगाहों में से प्रत्येक के लिए धागा का उपयोग करना ठीक होगा; 1,000 में से प्रत्येक के लिए एक धागा खराब होगा)। हालांकि किसी को थ्रेड बनाने से बचना चाहिए जो कि केवल थोड़े समय के लिए चलाएगा और छोड़ देगा, या प्रत्येक सीरियल पोर्ट के लिए समर्पित थ्रेड का उपयोग करके वास्तव में बड़ी संख्या में थ्रेड बनायेगा, यह सुनिश्चित करेगा कि जब डेटा आता है तो इसे संभालने के लिए तैयार धागा होगा।

+0

लिंक के लिए धन्यवाद मैंने इसका प्रयास किया। मेरे पास सेंसर को समर्पित धागा था और एक पैमाने पर समर्पित था। सेंसर अवरुद्ध होने पर स्केल थ्रेड केवल वज़न कम कर देता है (कुछ पैमाने पर था)। फिर एक बार वजन कम करने के बाद मैं द्वार को संभालने के लिए धागे को जन्म दूंगा। मैं इसे उस धागे पर कभी नहीं बनाऊंगा क्योंकि मुझे स्केल और सेंसर पढ़ने में त्रुटियां मिलीं। वे दो धागे एक साथ काम नहीं करेंगे। वे अलग-अलग COM बंदरगाहों और सबकुछ पर हैं, इसलिए मुझे यकीन नहीं है कि – CSharpDev

+0

क्या है मेरा सुझाव स्टार्टअप पर सभी थ्रेड लॉन्च करना होगा और बस उन्हें चलाना छोड़ देना होगा। धागे शुरू करना महंगा है। निरंतर निष्पादित कोड को थ्रेड छोड़कर बहुत महंगा है। आई/ओ के लिए इंतजार कर रहे धागे को छोड़कर, तुलनात्मक रूप से बहुत सस्ता है। इतना सस्ता नहीं है कि किसी को बिना किसी कारण के सैकड़ों चलना चाहिए, लेकिन इतना सस्ता है कि आठ आम तौर पर कोई बड़ा सौदा नहीं होगा। – supercat

1

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

जोड़ने के लिए संपादित: आप जो खो रहे हैं वह यह है कि आपको उस कोड को विभाजित करने की आवश्यकता है जो स्केल और कोड खोलता है और द्वार को बंद करता है। ऐसा करने का एक तरीका एक अनंत लूप होगा जो स्केल पर नज़र रखता है, और जब यह कुछ पता लगाता है, तो यह एक नया धागा शुरू करता है जो द्वार खोलने और बंद करने को संभालने में सक्षम होता है।

+0

उपरोक्त के लिए धन्यवाद चार्ली (और टॉम)। जो मैंने समझा, उससे मुझे लगता है कि लूप एक थ्रेड द्वारा "कारण" होता है जिसे दूसरे को बुलाया जाता है। – AlexDev

+0

गोटा, लेकिन फिर ओपी अभी भी प्रक्रियात्मक कोड का उपयोग कर रहा है - एक विधि तब तक नहीं चली जाएगी जब तक अन्य विधि इसे कॉल न करे। थ्रेडिंग में विचार एक कोड है जो दूसरे से स्वतंत्र होता है, और जब यह कुछ लंबा होता है (जैसे द्वार खोलना और बंद करना), यह उस नए काम में काम करता है। या क्या मैं कुछ न कुछ भूल रहा हूं? –

+0

मैं RunWorker पूर्ण विधि में थ्रेड लूप करता हूं। यह एक टाइमर शुरू करता है जो थ्रेड के बाद थ्रेड को कॉल करता है। – CSharpDev

2

मुझे लगता है कि आपको ऐसा कुछ चाहिए। के बाद से आप त्रुटियों

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int sensor = 1; 
    while(!SensorThread.CancellationPending == true) 
    { 
     int newSensor; 
     lock(this) 
     { 
      newSensor = ReadSensor(); 
     } 

     //sensor state changed 
     if(newSensor != sensor) 
     { 
      //sensor was 1 and changed to 0 
      if(newSensor==0) 
      { 
       scaleTimer.Start(); 
      } 
      sensor = newSensor; 
     } 
     Thread.Sleep(1); 
    } 
    e.Cancel = true; 
}  

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    //sensor blocked 
    //if (sensorstatus == 0) 
    { 
     lock(this) 
     { 
      ReadScale(); 
     } 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     lock(this) 
     { 
      SetOpenDelay(); 
      SetDuration(); 
     } 

     //if gate = 0, this means the weight of meat on scale 
     //is not in any weight range. Meat runs off the end. 
     if (gate == 0) 
     { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                      "lbs is out of range"}); 
     } 
     else 
     { 
     lock(this) 
     { 
     //open gate 
     } 
     lock(this) 
     { 
     //close gate 
     } 
     } 
    } 
+0

तो क्या नया सेंसर एक वास्तविक मूल्य के रूप में शुरू होना चाहिए? क्या आप यहां क्या कर रहे हैं उस पर थोड़ा सा विस्तार कर सकते हैं? – CSharpDev

+0

नया सेंसर प्रारंभिक फिक्स्ड। विचार, जैसा कि अन्य ने सुझाव दिया है, यह है कि सेंसर थ्रेड सेंसर की जांच करता है और जब यह राज्य में बदलाव का पता लगाता है तो यह स्केल थ्रेड को ट्रिगर करता है। – AlexDev

+0

मैं इसे एक शॉट दूंगा और देखें कि क्या होता है। धन्यवाद! – CSharpDev

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