0

내 C# 응용 프로그램은 백그라운드 작업자가 전송 된 데이터의 승인을 기다리는 데 사용됩니다. 여기에 몇 가지 사이비 코드는 내가 할 노력하고있어 시연 :BackgroundWorker를 사용하는 C#의 동시 스레드

UI_thread 
{ 
    TransmitData() 
    { 
     // load data for tx 
     // fire off TX background worker 
    } 

    RxSerialData() 
    { 
     // if received data is ack, set ack received flag 
    } 
} 

TX_thread 
{ 
    // transmit data 
    // set ack wait timeout 
    // fire off ACK background worker 
    // wait for ACK background worker to complete 
    // evaluate status of ACK background worker as completed, failed, etc. 
} 

ACK_thread 
{ 
    // wait for ack received flag to be set 
} 

무엇을 어떻게하면 ACK BackgroundWorker 구성 타임 아웃 및 승인이 수신되지 않습니다 것입니다. 그 장치가 전혀 변경되지 않았고 C# 응용 프로그램이 전송 중이기 때문에 그것이 원격 장치에 의해 전송되고 있음을 확신합니다. 비교 I는

DateTime dtThen = DateTime.Now(); 
DateTime dtNow; 
TimeSpan stTime; 

do 
{ 
    dtNow = DateTime.Now(); 
    stTime = dtNow - dtThen; 
} 
while ((stTime.TotalMilliseconds < waitTimeoutVar) && (!bAckRxd)); 

후자는 매우 애큐 리트 대기 시간을 발생 ... 이에 ... (이 작동 될 때)이으로부터

for(i = 0; (i < waitTimeoutVar) && (!bAckRxd); i++) 
{ 
    System.Threading.Thread.Sleep(1); 
} 

을 상기 ACK 스레드 변경된 전자에게. 그러나, 나는 슬립 기능의 제거가 직렬 데이터를 수신하는 능력을 방해하는지 궁금합니다. C#은 한 번에 하나의 스레드 만 실행할 수 있습니다. 즉, 다른 스레드를 실행할 수 있도록 잠시 스레드를 잠자기 상태로 설정해야합니까?

생각이나 제안이 있으면 감사하겠습니다. Microsoft Visual C# 2008 Express Edition을 사용하고 있습니다. 감사.

답변

3

RX 스레드의 "새"버전은 프로세서 시간의 100 %를 사용합니다. 단지 연속적으로 실행되기 때문에 절대로 사용하지 않습니다. 이 접근법의 일반적인 악의적 인 특성 외에도,이 일 수도 있습니다. (확실하지는 않지만) 데이터 수신과 같은 다른 일이 제 시간에 일어나지 않도록 방지합니다.

이와 같은 대기 시나리오의 경우 보통 이벤트이라는 스레드 동기화 구성을 사용합니다. "이벤트"개체를 만들고 RX 스레드가 기다리고있는 동안 처리 스레드 은 ACK를 받으면 이벤트를 알립니다.

AutoResetEvent event = new AutoResetEvent(false); 

// ... 
// ACK waiting thread: 
event.WaitOne(); 
// ... 

// ... 
// Whatever thread actually receives the ACK 
if (/* ack received */) 
{ 
    // bAckRxd = true; - comment this out. Replace with following: 
    event.Set(); 
} 

정확하게 ACK를받지 못하는 이유는 더 많은 정보가 필요합니다. 채널이 정확히 무엇입니까? 직렬 포트입니까? 회로망? 파이프? 다른 것?

+0

감사합니다. Fyodor. 그 트릭을 할 것으로 보인다. 직렬 통신을 사용하고 있습니다. –

+0

도움이 되니 기쁩니다. 천만에요. :-) –

3

C#이 한 번에 하나의 스레드 만 실행할 수 있는지 여부에 대한 직접적인 질문에 대답하기 위해 C#은 스레드와 아무 관련이 없습니다. 그러나 .NET Framework는 한 번에 여러 (논리) 스레드를 실행할 수 있습니다. 이것이 실제로 어떻게 처리되는지는 프레임 워크와 OS의 기능입니다.

귀하의 문제에 관해서는, 나는 당신이 대기 상태에서 너무 많은 스레드를 가지고 있다고 생각합니다. 데이터를 보내고받는 메소드에는 비동기 호출 모델이 있어야합니다 (시작과 종료). 이 때문에 Begin에 대한 호출로 전송을 시작한 다음 함수가 종료 될 때 호출되는 콜백을 첨부해야합니다.

그런 다음 콜백에서 결과를 처리하고 (필요한 경우) 다음 비동기 작업으로 진행하거나 UI를 업데이트합니다.

1

코드가 다소 실용적입니다. 그것은 당신이 문제를 일으킬 것으로 예상 할 때 참으로 당신을 곤경에 빠지게 할 수 있습니다. 특히 BGW 또는 스레드 풀 스레드를 사용할 때 스케줄러는 CPU 코어보다 많은 스레드가 활성화되어 있지 않을 때만 실행할 수 있습니다. 또는 스레드가 잠시 멈추는 경우. 너의 것이 붙어있다. 또한 이들을 효과적으로 사용하지 않는 것처럼 보이기 때문에 폴링 루프는 많은 불필요한 CPU 사이클을 소모합니다.SerialPort 클래스의의 기능이를 방지하기

활용 :

  • 당신은 전송 스레드가 필요하지 않습니다. 직렬 포트 드라이버에는 버퍼가 있으며 데이터가 버퍼에 맞으면 Write() 호출이 즉시 반환됩니다. 메인 쓰레드에서 쓰는 것이 좋습니다.
  • 수신 스레드가 반드시 필요한 것은 아닙니다. 직렬 포트에는 이미 하나가 있으며, DataReceived 이벤트가 실행됩니다. 데이터를 전송할 때 시작한 타이머를 충돌시킬 수 있습니다.
  • SerialPort에는 이미 ReadTimeout 속성이 있습니다. 수신 스레드에서이를 사용하여 Read() 호출을 시간 종료 할 수 있습니다.

슬립()은 직렬 포트를 방해하지 않으므로 드라이버는 하드웨어 인터럽트를 사용하여 데이터를 읽습니다.

+0

예, 동의합니다. 4 명의 백그라운드 작업자 중 2 명을 제거하고 Fyodor가 제안한 AutoResetEvent를 구현했습니다. SerialPort 클래스에 대해 자세히 살펴보아야 할 것이다. 감사. –

관련 문제