2010-05-11 118 views
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#应用程序正在传输。我从这里改变了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)); 

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

任何想法或建议,你可能会感激。我正在使用Microsoft Visual C#2008速成版。谢谢。

回答

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

谢谢,费奥多尔。这似乎是诀窍。我正在使用串行通信。 – 2010-05-11 20:34:34

+0

很高兴帮助。别客气。 :-) – 2010-05-11 22:25:24

3

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

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

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

1

你的代码是相当快乐的。当你希望他们计时时,这确实会让你陷入麻烦。特别是当您使用BGW或线程池线程时,调度程序只允许它们在没有更多线程处于活动状态时运行,而不是CPU核心。或者当线程“卡住”了一段时间。你的卡住了。您似乎也没有有效地使用它们,轮询循环会消耗大量不必要的CPU周期。

杠杆SerialPort类的功能,以避免这种情况:

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

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

+0

是的,我同意。我消除了4个背景工作者中的2个,并实施了由Fyodor建议的AutoResetEvent。我将不得不仔细看看SerialPort类。谢谢。 – 2010-05-11 20:33:46

相关问题