2009-08-22 4 views
1

최근에는 직렬 통신을 수행하여 읽기, 쓰기 등을 담당하는 모든 Windows API 함수에 대한 간단한 인터페이스 인 클래스를 준비했습니다. 모든 I/O 작업 이 클래스 내부는 비동기 적으로 처리됩니다.중복 된 I/O 작업 중 직렬 포트 및 처리 오류

필자가 질문하기 전에 직렬 포트에서 데이터를 쓰고 읽는 방법을 보여 주겠다. (필기체의 구조가 정확히 동일하므로 프리젠 테이션에 아무런 요점도 없습니다. 둘 다).

function TSerialPort.Read(var pBuffer; const lBufferSize: Cardinal): Cardinal; 
var 
    lOverlapped: OVERLAPPED; 
    lLastError: Cardinal; 
    lEvent: TEvent; 
begin 
    lEvent := TEvent.Create(nil, True, False, ''); 
    try 
    FillChar(lOverlapped, SizeOf(lOverlapped), 0); 
    lOverlapped.hEvent := lEvent.Handle; 

    if not ReadFile(FSerialPortHandle, pBuffer, lBufferSize, Result, @lOverlapped) then 
    begin 
     lLastError := GetLastError; 
     if (lLastError <> ERROR_IO_PENDING) and (lLastError <> ERROR_SUCCESS) then 
     raise Exception.Create(SysErrorMessage(lLastError)); 

     case lEvent.WaitFor(INFINITE) of 
     wrSignaled: 
      if not GetOverlappedResult(FSerialPortHandle, lOverlapped, Result, False) then 
      raise Exception.Create(SysErrorMessage(GetLastError)); 

     wrError: 
      begin 
      lLastError := lEvent.LastError; 
      //this is a call to Windows.CancelIo(FSerialPortHandle); 
      if Self.CancelIO() then 
       lEvent.WaitFor(INFINITE); 
      raise Exception.Create(SysErrorMessage(lLastError)); 
      end; 
     end; 
    end; 
    finally 
    FreeAndNil(lEvent); 
    end; 
end; 

이 기능이 완료 될 때까지 읽기 작업을 기다리는 동안은 중복 작업에 시리얼 포트를 열 왜 나 한테 물어 전에

가 여기 내 설명입니다 - 직렬 포트를 여는 경우에만이 방법은 내가 시간 WaitCommEvent을 (지정할 수 있습니다) 방법 이벤트를 기다린다. 겹치지 않는 작업을 위해 포트를 열면 직렬 포트에 이벤트가 나타날 때까지 WaitCommEvent()가 차단되어 항상 호출 스레드가 영원히 차단되지 않을 수 있습니다.

그럼에도 불구하고, 위의 Read() 함수에 집중하겠습니다.

1) 우선 이벤트를 설정할 시간 제한없이 대기합니다. 거기 때문에 현재 스레드가 그 이유 때문에 영원히 차단 될 가능성이 있습니까? 나는 비동기 적으로 읽기 작업을 수행하는 스레드에 의해 이벤트가 조만간 설정 될지 100 % 확신 할 수 있는지 여부를 알지 못합니다. 직렬 포트의 읽기 타임 아웃이 모두 0으로 설정되면 주어진 바이트 수를 읽을 때까지 읽기 작업이 완료되지 않는다는 것을 알고 있습니다. 그러나 이것은 제가 알고있는 동작입니다. 내 질문에 이벤트가 설정되지 않을 것입니다 예기치 않은 상황과 WaitFor() 메서드를 영원히 기다릴 우려 - 그것은 일어날 가능성이 높습니다?

2) WaitFor()는 대기 작업 중 일부 오류가 발생했음을 알리는 wrError를 반환 할 수 있습니다 (단, 중복 된 읽기 작업과 연결되지는 않습니다). 따라서 더 이상 읽을 작업이 끝날 때까지 기다릴 필요가 없다고 생각합니다. 이벤트 핸들이 더 이상 사용할 수 없기 때문입니다. 맞습니까? 그래서 CancelIO() 메서드를 호출하여 읽기 작업을 취소하고 비동기 적으로 취소 된 읽기를 수행 한 스레드가 이벤트를 설정하고 예외를 발생시킬 때까지 기다립니다. 내가 그 스레드에 의해 취소 될 때까지 기다릴 것이기 때문에 나는 (Read/Write) I/O를 취소하지 않고 즉시 Read() 메소드를 떠났기 때문에, 그 쓰레드가 그 데이터 (겹쳐진 레코드 데이터)를 로컬 변수에 쓰게 할 것이다. 더 이상 유효하지 않아요, 그렇죠? 한편, 예외를 발생시키기 전에 WaitFor (INFINITE) 호출로 인해 현재 스레드가 영구적으로 차단 될 위험이 있습니까?

위의 진술이 사실인지 아닌지 알려 주시면 의견을 보내 주시면 감사하겠습니다.

대단히 감사합니다.

답변

1

궁금증에서 벗어나서 : 기존 직렬 부품을 사용하지 않으시겠습니까?

나는 GPS 메시지를 수신 TurboPower Async를 사용하지만 자유롭게 사용할 다른 사람의 많음이있다 : http://www.efg2.com/Lab/Library/Delphi/IO/PortIO.htm

사람들의 대부분은 모두 낮은 수준의 IO 및 스레드를 멀리 추상화, 당신은 훨씬 더 높은 수준에서 시리얼 통신을 할 수 있도록 너를 위해서.

그런 식으로 수신하려면 onreceive 처리기 만 작성하고 send()으로 전화하면 걸릴 수 있습니다.

+0

제안 해 주셔서 감사합니다.당신 말이 맞을지 모르지만 나는 여전히 내 질문에 대한 답을 알고 싶다. 그것은 나의 호기심이나 오히려 그 주제에 대한 나의 지식을 넓히고 싶다. –