2012-01-12 10 views
5

मेरे पास एक विनफॉर्म प्रोग्राम है जो SerialPort पर कुछ एसिंक्रोनस आईओ करता है। हालांकि, मैं नियमित रूप से SerialPort.Close() कॉल पर ठंडे प्रोग्राम के साथ किसी समस्या में चल रहा हूं, जो यादृच्छिक रूप से यादृच्छिक रूप से है।सी # WinialPort पर Winform ठंड।

मुझे लगता है कि यह एक थ्रेड सुरक्षा समस्या है, लेकिन मुझे यकीन नहीं है कि यह कैसे ठीक किया जाए। मैंने पोर्ट ओपन/क्लोज फ़ंक्शंस के साथ एसिंक डेटा रीसेस्ड हैंडलर को जोड़ने/हटाने और बंदरगाह पर इन और आउट बफर को हटाने का प्रयास किया, लेकिन ऐसा कुछ नहीं लगता है। मुझे लगता है कि महत्वपूर्ण SerialPort कोड के नीचे है:

using System; 
using System.Collections.Generic; 
using System.IO.Ports; 

public class SerialComm 
{ 
    private object locker = new object(); 

    private SerialPort port; 
    private List<byte> receivedBytes; 

    public SerialComm(string portName) 
    { 
    port = new SerialPort(portName); 
    port.BaudRate = 57600; 
    port.Parity = Parity.None; 
    port.DataBits = 8; 
    port.StopBits = StopBits.One; 

    receivedBytes = new List<byte>(); 
    } 

    public void OpenPort() 
    { 
    if(port!=null && !port.IsOpen){ 
     lock(locker){ 
     receivedBytes.Clear(); 
     } 

     port.DataReceived += port_DataReceived; 
     port.Open(); 
    } 
    } 

    public void ClosePort() 
    { 
    if(port!=null && port.IsOpen){ 
     port.DataReceived -= port_DataReceived; 
     while(!(port.BytesToRead==0 && port.BytesToWrite==0)){ 
     port.DiscardInBuffer(); 
     port.DiscardOutBuffer(); 
     } 
     port.Close(); 
    } 
    } 

    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
    try{ 
     byte[] buffer = new byte[port.BytesToRead]; 
     int rcvdBytes = port.Read(buffer, 0, buffer.Length); 

     lock(locker){ 
     receivedBytes.AddRange(buffer); 
     } 

     //Do the more interesting handling of the receivedBytes list here. 

    } catch (Exception ex) { 
     System.Diagnostics.Debug.WriteLine(ex.ToString()); 
     //put other, more interesting error handling here. 
    } 
    } 
} 

अद्यतन

के लिए धन्यवाद @ Afrin के जवाब यूआई धागे से गतिरोध हालत (This blog post यह वर्णन एक अच्छा काम करता है, और कई अन्य देता है उनका कहना है अच्छी युक्तियाँ), मैंने एक साधारण परिवर्तन किया है, और अभी तक त्रुटि को पुन: उत्पन्न करने में सक्षम नहीं है!

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    try{ 
    byte[] buffer = new byte[port.BytesToRead]; 
    int rcvdBytes = port.Read(buffer, 0, buffer.Length); 

    lock(locker){ 
     receivedBytes.AddRange(buffer); 
    } 

    ThreadPool.QueueUserWorkItem(handleReceivedBytes); 

    } catch (Exception ex) { 
    System.Diagnostics.Debug.WriteLine(ex.ToString()); 
    //put other, more interesting error handling here. 
    } 
} 

private void handleReceivedBytes(object state) 
{ 
    //Do the more interesting handling of the receivedBytes list here. 
} 

उत्तर

13

कारण लटका होगा जब आप बंद (आमतौर आह्वान को फोन करके) क्योंकि आपके serialport वस्तु

आप मुख्य थ्रेड के साथ एक कॉल को सिंक्रनाइज़ कर रहे हैं के ईवेंट हैंडलर में यह है। SerialPort की करीबी विधि इसके EventLoopRunner थ्रेड के लिए प्रतीक्षा करती है जो डेटारेसेव/त्रुटि/पिन चेंज किए गए ईवेंट को समाप्त करने के लिए निकाल देती है। लेकिन चूंकि इस कार्यक्रम में आपका कोड मुख्य धागे का जवाब देने का इंतजार कर रहा है, इसलिए आप मृत लॉक स्थिति में भाग लेते हैं।

समाधान: BeginInvoke आह्वान के बजाय का उपयोग करें: https://connect.microsoft.com/VisualStudio/feedback/details/202137/serialport-close-hangs-the-application

संदर्भ: http://stackoverflow.com/a/3176959/146622

+0

यकीन है कि मैं तुम्हें सही ढंग से समझ, सारांश में, वहाँ 'Read' और के बीच' SerialPort' के भीतर एक गतिरोध है बनाने के लिए 'बंद करें' कॉल? – chezy525

+0

आप जिस तरह से आप port_DataReceived ईवेंट हैंडलर में यूआई तत्व अपडेट आह्वान बदलना होगा, BeginInvoke का उपयोग आह्वान के बजाय अद्यतन करने के लिए, या समाधान में वर्णित के रूप घटना को संभालने के लिए एक और धागा का उपयोग करें। – Afshin

+0

किसी भिन्न थ्रेड पर UI के लिए डेटा को संभालने से समस्या हल हो गई है। धन्यवाद! – chezy525