C# c中线程模式的正确回调#
我正在使用线程从我的程序连接到多个客户端(PLC)。程序将发送数据并从PLC接收响应。。我遇到的问题是,在调试模式下,(切换断点)一次执行一步..程序运行得很好!,收到的ID确认它来自某个线程。。但是,如果我只是调试而不切换任何断点,响应事件将收到相同的ID,尽管在不同的线程上。。有什么不对的 下面是我的代码 启动请求:C# c中线程模式的正确回调#,c#,multithreading,events,asynchronous,C#,Multithreading,Events,Asynchronous,我正在使用线程从我的程序连接到多个客户端(PLC)。程序将发送数据并从PLC接收响应。。我遇到的问题是,在调试模式下,(切换断点)一次执行一步..程序运行得很好!,收到的ID确认它来自某个线程。。但是,如果我只是调试而不切换任何断点,响应事件将收到相同的ID,尽管在不同的线程上。。有什么不对的 下面是我的代码 启动请求: private void StartRequest() { foreach (ModbusTCP work in works) {
private void StartRequest()
{
foreach (ModbusTCP work in works)
{
work.Connect();
Thread.Sleep(1000);
if (work.Connected)
{
try
{
Thread thread = new Thread(new ThreadStart(() => work.StartReadHoldingRegister())) {
Name = ((ReadHoldingRegisterParam)work.SetReadHoldingRegisterParam).id.ToString(),
IsBackground = true
};
work.OnResponseEvent += new EventHandler<ModbusTCP.ResponseEventArgs>(modbus_OnResponseEvent);
work.OnExceptionEvent += new EventHandler<ModbusTCP.ExceptionEventArgs>(modbus_OnExceptionEvent);
thread.Start();
threads.Add(thread);
}
catch (ThreadStateException ex)
{
MessageBox.Show(ex.Message);
}
}
else
work.Disconnect();
}
}
变量
work
在线程之间共享。执行线程后,它接受变量work
的任何值。这取决于每个线程的处理速度。当您使用调试器单步执行代码时,您不会遇到这种情况
如果在匿名方法之前捕获该值,则可以:
try
{
// capture the current value of the loop variable
ModbusTCP localWork = work;
// so the anonymous method uses the reference in localWork
// instead of whatever value work has, which can be anywhere
// the future, worst case after your loop is finished, where
// work would hold the last value of the loop, and then
// start all threads with that value.
Thread thread = new Thread(
new ThreadStart(
() => localWork.StartReadHoldingRegister()))
{
Name = ((ReadHoldingRegisterParam) localWork.SetReadHoldingRegisterParam).id.ToString(),
IsBackground = true };
});
localWork.OnResponseEvent += new EventHandler<ModbusTCP.ResponseEventArgs>(modbus_OnResponseEvent);
localWork.OnExceptionEvent += new EventHandler<ModbusTCP.ExceptionEventArgs>(modbus_OnExceptionEvent);
试试看
{
//捕获循环变量的当前值
ModbusTCP localWork=工作;
//因此,匿名方法使用localWork中的引用
//而不是任何有价值的工作,它可以在任何地方
//将来,循环完成后的最坏情况,在哪里
//功将保持循环的最后一个值,然后
//使用该值启动所有线程。
线程=新线程(
新ThreadStart(
()=>localWork.StartReadHoldingRegister())
{
Name=((ReadHoldingRegisterParam)localWork.SetReadHoldingRegisterParam.id.ToString(),
IsBackground=true};
});
localWork.OnResponseEvent+=新事件处理程序(modbus_OnResponseEvent);
localWork.OneExceptionEvent+=新事件处理程序(modbus_OneExceptionEvent);
旁注:
lock (lockingObject)
{
if (e.data.Length > 0)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
此代码不太可能是正确的。在这里,您将在原始线程中获得一个锁,然后提交一个新操作async。锁的作用域是当前方法,因此将在BeginInvoke
调用返回时释放锁,而不是在操作本身期间。锁实际保护的唯一操作是e.data.Length
检查,它在参数(非共享)状态下运行,因此不需要保护
将锁放在操作中更有意义,但是操作总是在主线程上执行,因此不太可能真正需要保护(因为基本上是单线程的)。在看不到整个代码的情况下,很难准确地猜测您想要实现什么,但是,
lock(lockingObject)
不太可能是必要的,或者是有用的。我明白您的意思,实际上锁一开始就不存在。我非常绝望地试图解决这个问题,并且几乎在所有地方都随机地锁上了锁。幸运的是,rene想出了一个很好的解释,我完全没有注意到我遗漏了什么。。。一旦线程被执行,它将接受变量work的任何值
lock (lockingObject)
{
if (e.data.Length > 0)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{