0

我的 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# 应用程序正在传输。我已经从这里更改了 ack 线程(当它工作时)......

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

……到这……

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

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

与前者相比,后者产生非常准确的等待时间。但是,我想知道删除睡眠功能是否会干扰接收串行数据的能力。C#是否一次只允许一个线程运行,也就是说,我是否必须在某个时间让线程休眠以允许其他线程运行?

您可能有的任何想法或建议将不胜感激。我正在使用 Microsoft Visual C# 2008 Express Edition。谢谢。

4

3 回答 3

3

为了回答 C# 是否允许一次运行一个线程的直接问题,C# 与线程无关。但是,.NET 框架将允许您一次运行多个(逻辑)线程。如何实际处理是框架和操作系统的功能。

至于你的问题,我认为你有太多的线程处于等待状态。您发送和接收数据的方法应该有异步调用模型(开始和结束)。因此,您应该通过调用 Begin 开始传输,然后附加一个在函数终止时调用的回调。

然后,在回调中,您将处理结果并继续下一个异步操作(如有必要)或更新 UI。

于 2010-05-11T17:18:22.403 回答
3

您的“新”版本的 RX 线程正在使用 100% 的处理器时间——它只是连续运行并且从不休眠。除了这种方法的一般邪恶性质之外,这可能(尽管不确定)会阻止其他一些事情,如接收数据,按时发生。

对于这样的等待场景,通常会使用一种称为event的线程同步结构。您创建一个“事件”对象,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,我需要更多信息。渠道具体是什么?是串口吗?网络?管道?还有什么?

于 2010-05-11T17:22:05.577 回答
1

您的代码相当线程快乐。当您期望他们计时时,这确实会给您带来麻烦。尤其是当您使用 BGW 或线程池线程时,调度程序仅允许它们在活动线程不超过 CPU 内核数时运行。或者当线程“卡住”一段时间时。你的卡住了。您似乎也没有有效地使用它们,轮询循环会消耗大量不必要的 CPU 周期。

利用 SerialPort 类的功能来避免这种情况:

  • 您不需要传输线程。串行端口驱动程序有一个缓冲区,当数据适合缓冲区时,您的 Write() 调用将立即返回。从主线程编写很好。
  • 您不一定需要接收线程。串口已经有一个,它运行 DataReceived 事件。它可以碰撞您在传输数据时启动的计时器。
  • SerialPort 已经有一个 ReadTimeout 属性。您可以在接收线程中使用它来超时 Read() 调用。

Sleep() 不会干扰串行端口,它们的驱动程序使用硬件中断读取数据。

于 2010-05-11T19:37:46.137 回答