C#中使用BackgroundWorker的并发线程

发布于 2024-08-31 23:35:48 字数 1244 浏览 10 评论 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。谢谢。

My C# application is such that a background worker is being used to wait for the acknowledgement of some transmitted data. Here is some psuedo code demonstrating what I'm trying to do:

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
}

What happens is that the ACK BackgroundWorker times out, and the acknowledgement is never received. I'm fairly certain that it is being transmitted by the remote device because that device has not changed at all, and the C# application is transmitting. I have changed the ack thread from this (when it was working)...

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

...to this...

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

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

The latter generates a very acurate wait time, as compared to the former. However, I am wondering if removal of the Sleep function is interferring with the ability to receive serial data. Does C# only allow one thread to run at a time, that is, do I have to put threads to sleep at some time to allow other threads to run?

Any thoughts or suggestions you may have would be appreciated. I am using Microsoft Visual C# 2008 Express Edition. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦回旧景 2024-09-07 23:35:48

您的“新”版本的 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,我需要更多信息。渠道到底是什么?是串口吗?网络?管道?还有别的事吗?

Your "new" version of RX thread is utilizing 100% of processor time - it just runs continuously and never sleeps. Besides the general evil nature of this approach, this might (although not certainly) prevent some other things, like receiving data, from happening on time.

For wait scenarios like this, one would usually utilize a thread synchronization construct called event. You create an "event" object, and the RX thread waits on it, while the processing thread signals the event when the ACK is received.

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();
}

As for why exactly you're not receiving your ACK, I need more information. What exactly is the channel? Is it a serial port? Network? Pipe? Something else?

陌上芳菲 2024-09-07 23:35:48

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

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

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

To answer the direct question of whether or not C# allows one thread to run at a time, C# doesn't have anything to do with threading. The .NET framework, however, will allow you to run multiple (logical) threads at a time. How that is actually handled is a function of the framework and the OS.

As for your problem, I think you have too many threads in a wait state to begin with. Your methods to send and receive the data should have async call models on them (Begin and End). Because of this, you should start your transmission with a call to Begin and then attach a callback which is called when the function terminates.

Then, in the callback, you would process the result and proceed to the next async operation (if necessary) or update the UI.

不顾 2024-09-07 23:35:48

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

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

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

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

Your code is rather thread-happy. That can indeed get you in trouble when you expect them to time stuff. Especially when you use BGW or thread pool threads, the scheduler only allows them to run when there are not more threads active than you have CPU cores. Or when threads get "stuck" for a while. Yours get stuck. You also don't seem to use them effectively, polling loops burn a lot of needless CPU cycles.

Leverage the capabilities of the SerialPort class to avoid this:

  • You don't need a transmit thread. The serial port driver has a buffer, your Write() call will instantly return when the data fits the buffer. Writing from the main thread is fine.
  • You don't necessarily need a receive thread. Serial port already has one, it runs the DataReceived event. It can bump a Timer that you started when you transmitted the data.
  • SerialPort already has a ReadTimeout property. You can use it in a receive thread to timeout the Read() call.

Sleep() doesn't interfere with serial ports, their drivers read data using hardware interrupts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文