2011-05-13 1 views
7

현재 직렬 연결을 통해 통합 서보와 통신하는 응용 프로그램을 작성 중입니다.직렬 포트 데이터 구문 분석의 가장 빠른 멀티 스레딩 방법 C#

모터가 최대 1000 번/초 속도로 위치 데이터를 보냅니다. 내가 얻으려고하는 것은 다시 오는 데이터 (공백, 줄 바꿈 등을 제거하여)를 포맷하고 수신 된 문자열에서 관련 데이터를 추출하기 위해 구문 분석 할 수있게하는 것입니다.

현재 데이터 수신 이벤트 핸들러에서 데이터를 읽고 일련의 string.replace 메소드 호출을 사용하여 형식을 지정하며 버퍼로 작동하는 문자열에 추가합니다. 그런 다음 스레드를 사용하여, 모터에서 한 메시지의 끝을 의미하는 특정 구분 기호 (내 경우 "\ r")를 채운 다음 지속적으로 버퍼를 검사하여 버퍼에서 메시지를 제거하고이를 부자에게 인쇄합니다 텍스트 필드.

이 방법에는 두 가지 문제점이 있습니다. 하나는 모터가 높은 속도로 데이터를 위치시키기 때문에 버퍼가 데이터가 스레드에 의해 처리 될 수있는 것보다 빠르게 채워진다는 것입니다. 따라서 모터에 명령을 보내면 즉시 작동하지만 버퍼의 모든 선행 데이터를 먼저 처리해야하기 때문에 응답이 몇 초 지연됩니다. 둘째, while (true) 구조를 구현하는 메서드를 실행하는 두 개의 스레드를 사용하면 프로세서 사용률이 급격히 올라가고 몇 초 내에 PC의 팬이 최대 상태가됩니다.

더 나은 데이터 처리 방법이 있습니까? 일반적으로

private void parseBuffer() 
    { 
     while (true) 
     { 
      //obtain lock, parse one message from buffer 
      lock (this) 
      { 
       if (readBuffer.IndexOf("\r") > 0) 
       { 
        String t = readBuffer.Substring(0, readBuffer.IndexOf("\r") + 1); 
        readBuffer = readBuffer.Replace(t, ""); 
        dataReady(this, new CustomEventArgs(t, null)); 
       } 
      } 
     } 
    } 
+2

문제점을 발견했습니다. 프로그램이 버퍼의 데이터를 충분히 빠르게 처리 할 수있는 것은 아닙니다. 프로그램이 리치 텍스트 상자에 충분히 빨리 쓸 수 없습니다. 내가 사용하고 있던 코드는'textBox1.text + = myText; '. 콘솔로 인쇄 할 때, 앞서 말했듯이, 프로그램이 데이터를 처리하는 것보다 빠르게 버퍼가 커지면 문제가 없습니다. – isometrik

답변

0

내가 전적으로에서 읽는 독자 스레드 사이에 차단 모음을 사용합니다 : 여기

//data recieved event handler 
    private void dataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 
    { 
     string tmp; 

      tmp = sp.ReadExisting(); 

      //cut out any unnecessary characters 
      tmp = tmp.Replace("\n", ""); 
      tmp = tmp.Replace(",", "\r"); 
      tmp = tmp.Replace(" ", ""); 

      lock (this) 
      { 
       //put all received data into the read buffer 
       readBuffer += tmp; 
      } 

    } 

는 스레드가 실행하는 방법입니다 : 여기

내 이벤트 처리기 코드 소켓과 파싱 스레드
성능 측면에서 보면 split for parsing을 사용하면 문자열 내부를 교체하는 것보다 훨씬 빠릅니다. 당신은 정규 표현식 및/또는 StringBuilder 클래스를 사용하여 보라 - 당신은 정규식 코드는 다음과 같을 것이다 대안
1 식을 사용한다 :

string pattern = " |\\n|\\r"; 
string replacement = " "; 
regex rgx = new Regex(pattern); 
string result = rgx.Replace(input, replacement); 
+0

하지만 내 목표가 캐릭터를 제거하는 경우, 나는 분할 명령과 연결 명령을 모두 사용해야합니다. 이것은 여전히 ​​더 빠를 것입니까? – isometrik

+0

왜 문자를 먼저 제거하는지 - 정말 비싼 작업입니다 - 실제 메모리 문제가있는 경우에만 이것을 수행하십시오. – weismat

2

당신이 할 수있는 몇 가지가 개선 할 수있다 이것은 극적으로.

1) 입력 데이터를 한 번에 한 문자 씩 파싱하는 상태 머신 파서를 작성하십시오. 완전한 "메시지"를 만들었 으면 List<MyMessage> 구조에 추가하십시오.

2) 가상화 된 ListView 또는 DataGridView를 사용하여 List<MyMessage>을 표시합니다.

3

parseBuffer은 마지막 시도 이후 새로운 데이터가 없어도 야생 회전합니다.

신호로 완화 할 수 있습니다.

private AutoResetEvent waitHandle = new AutoResetEvent(false); 

은 트리거 이벤트를 수신 데이터 parseBuffer

private void parseBuffer() 
{ 
    while (true) 
    { 
     waitHandle.WaitOne(); // <-- waits until there is more data to parse 
     //obtain lock, parse one message from buffer 
     lock (this) 
     { 
      if (readBuffer.IndexOf("\r") > 0) 
      { 
       String t = readBuffer.Substring(0, readBuffer.IndexOf("\r") + 1); 
       readBuffer = readBuffer.Replace(t, ""); 
       dataReady(this, new CustomEventArgs(t, null)); 
      } 
     } 
    } 
} 
+0

여러 메시지를 버퍼에 동시에 배치 할 수 없다면 waitHandle을 설정하면 하나의 메시지 만 처리됩니다. while (readBuffer.IndexOf ("\ r")> 0) "에 (readBuffer.IndexOf ("r "> 0)"을 변경했습니다.) – isometrik

+0

guidiline 당 잠금을 피하십시오. –

+0

TCP 스트림과 같은 비트를 사용하는 경우 1 수신 작업에서 여러 개의 전송을 수신 할 수 있기 때문에 기대 한 것보다 더 많은 잠재성에 대해 수신 확인을해야합니다 –

0

의 신호 dataReceived

//data recieved event handler 
private void dataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 
{ 
    string tmp; 

     tmp = sp.ReadExisting(); 

     //cut out any unnecessary characters 
     tmp = tmp.Replace("\n", ""); 
     tmp = tmp.Replace(",", "\r"); 
     tmp = tmp.Replace(" ", ""); 

     lock (this) 
     { 
      //put all received data into the read buffer 
      readBuffer += tmp; 
      waitHandle.Set(); // <-- tell parseBuffer that new data is available 
     } 

} 

기다렸다가 신호 큐 원시 바이트 저장소로 들어오는 데이터를 읽는다. 이벤트 처리기에서 데이터를 처리하지 마십시오. 그런 다음 다른 방법으로 데이터를 처리하기 위해 알빈이 말한 것과 비슷한 것을 사용하십시오. 중요한 것은 eventhandler가 가능한 자주 실행되도록하고 더 이상 필요하지 않도록하는 것입니다.