Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# c中线程模式的正确回调#_C#_Multithreading_Events_Asynchronous - Fatal编程技术网

C# c中线程模式的正确回调#

C# c中线程模式的正确回调#,c#,multithreading,events,asynchronous,C#,Multithreading,Events,Asynchronous,我正在使用线程从我的程序连接到多个客户端(PLC)。程序将发送数据并从PLC接收响应。。我遇到的问题是,在调试模式下,(切换断点)一次执行一步..程序运行得很好!,收到的ID确认它来自某个线程。。但是,如果我只是调试而不切换任何断点,响应事件将收到相同的ID,尽管在不同的线程上。。有什么不对的 下面是我的代码 启动请求: private void StartRequest() { foreach (ModbusTCP work in works) {

我正在使用线程从我的程序连接到多个客户端(PLC)。程序将发送数据并从PLC接收响应。。我遇到的问题是,在调试模式下,(切换断点)一次执行一步..程序运行得很好!,收到的ID确认它来自某个线程。。但是,如果我只是调试而不切换任何断点,响应事件将收到相同的ID,尽管在不同的线程上。。有什么不对的

下面是我的代码

启动请求:

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(() =>
        {