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) );
与前者相比,后者生成了非常准确的等待时间。但是,我想知道删除睡眠功能是否会干扰接收串行数据的能力。 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的“新”版本的 RX 线程正在利用 100% 的处理器时间 - 它只是连续运行并且从不休眠。除了这种方法的普遍邪恶本质之外,这可能(尽管不是一定)会阻止其他一些事情(例如接收数据)按时发生。
对于这样的等待场景,通常会使用称为事件的线程同步构造。您创建一个“事件”对象,RX 线程等待它,而处理线程在收到 ACK 时向事件发出信号。
至于为什么您没有收到 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.
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?
为了回答 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.
您的代码非常适合线程。当你期望他们计时时,这确实会给你带来麻烦。特别是当您使用 BGW 或线程池线程时,调度程序仅允许它们在活动线程数不超过 CPU 核心数时运行。或者当线程“卡住”一段时间时。你的卡住了。您似乎也没有有效地使用它们,轮询循环消耗了大量不必要的 CPU 周期。
利用 SerialPort 类的功能来避免这种情况:
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:
Sleep() doesn't interfere with serial ports, their drivers read data using hardware interrupts.