我正在使用线程从我的程序连接到多个客户端(PLC)。程序将发送数据并从PLC接收响应。问题是,当处于调试模式时,(切换断点)一次一步......程序工作非常好!,接收到的ID确认它来自其中一个线程..但如果我只是调试而不切换任何断点,响应事件将收到相同的ID,虽然在不同的线程上......可能是错误的......
Debugging mode with breakpoint:
Debugging mode without breakpoint:
以下是我的代码
开始申请:
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();
}
}
回应事件
private void modbus_OnResponseEvent(object sender, ModbusTCP.ResponseEventArgs e)
{
lock (lockingObject)
{
if (e.data.Length > 0)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
AddRow(RcvDataGrid, new PLCPacket() {
PLCId = e.id.ToString(),
PLCIp = "Test",
PLCTime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt"),
PLCData = ""
});
}));
}
}
}
答案 0 :(得分:4)
您的变量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);
答案 1 :(得分:0)
旁边评论:
lock (lockingObject)
{
if (e.data.Length > 0)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
此代码不太可能正确。在这里,您将获得原始线程中的锁定,然后提交新操作async。锁定范围为当前方法,因此将在BeginInvoke
调用返回后立即释放,而不是在操作本身期间释放。锁实际保护的唯一操作是e.data.Length
检查,它在参数(非共享)状态下运行,因此不需要保护。
将锁置于操作中会更有意义,但操作总是在主线程上执行,因此实际上不太可能需要保护(因为基本上是单线程)。很难准确地猜测你想要实现的是什么,而不是看到整个代码,但是lock(lockingObject)
不太可能是必要的或有用的。