值在调用开始之前的迭代中被更改 [英] Value getting changed in the iteration before the call begins

查看:102
本文介绍了值在调用开始之前的迭代中被更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用中包含以下代码。

  MyEventHandler handler = null; //声明处理程序

foreach(组中的字符串pname)
{
handler = getHandler(pname); //获取处理程序
if(handler == null)
{
throw new KeyNotFoundException(找不到用户 + pname +);
}
//调用处理程序
handler.BeginInvoke(this,e,new AsyncCallback(EndAsync),null);
}

所以我得到了处理程序并调用 BeginInvoke 方法。但是在 BeginInvoke 被调用之前,它进入下一次迭代,并且处理程序值被更改。因此, BeginInvoke 正在参与这个新的处理程序。



希望您明白我的意思。那么我该如何消除这个问题呢?我不想在 BeginInvoke 之后打电话叫睡眠,因为我觉得这是浪费时间。



有什么想法吗?



Update1
我很确定在调用BeginInvoke()之前,处理程序对象已更改。我想BeginInvoke需要一些时间来创建一个单独的线程来调用其他函数。



Update2
WCF服务,客户端调用一个函数,该函数又利用此函数。我为每个客户端分别在服务器中存储了处理程序。 WCF服务与客户端具有单独会话的双工合同。我看到执行此功能后,同一用户被调用两次。但是我放了一个断点并对其进行调试(这为BeginInvoke提供了调用该函数所需的时间),它可以完美地工作。我非常确定我在线程中也遇到了这个问题,因为我在一个循环中创建了多个线程。如果线程委托具有参数a,b,c,并且如果您在下一次迭代的开始对其进行更改,则会发生相同的行为。我不知道你们中有多少人以前曾遇到过这个问题。如果我放置了Sleep()或制作了处理程序的副本并使用副本调用它,它将起作用。



Update3



好的,我已经测试过了。我只是按如下方式添加了Thread.Sleep()。

  chatTo.BeginInvoke(this,e,new AsyncCallback(EndAsync),空值); 
Thread.Sleep(500);

,它就像一种魅力一样工作。有什么想法吗?



更新4



我创建了一个线程示例来演示问题和我已在此处上传 。我希望对此的解决方案也能解决我的问题。请检查示例。

解决方案

我不知道为什么会发生这种情况-您发布的代码可能无法重现您的行为描述。完全合理的是,BeginInvoke调用可能不会立即实际执行任何操作,并且下一次迭代可能会在您实际看到该调用执行任何操作之前发生-因为它将被工作线程排队等待处理。



这并不意味着正在调用其他处理程序-调用BeginInvoke时将立即捕获要调用的处理程序,因此本地



另外-为什么在这里锁了?除非多个线程在相同的可枚举数上同时进行此处理(在这种情况下,您为什么要这样做),否则我看不到您为何会锁定的任何原因。



我还要说的是,如果您根据调试器中看到的内容来判断这种行为,那么您就不必担心-这样,您将获得调试器的有趣结果,并且其中包含多个线程



问题是-您的程序实际上在做什么吗?如果是这样,但是您在调试时看到这种奇怪的行为-那是完全正常的。



正如一些评论所指出的那样,您发布的代码可能不完全是什么导致了问题。例如,如果处理程序是在多个线程之间共享的局部变量,然后执行此迭代,那么可以,您会得到类似的信息。但是,方法局部变量只能由当前该方法中的同一线程修改(并确实读取);该规则的唯一例外是,然后将 handler 引用作为 ref 传递给另一个线程方法。 / p>

I've the following code in my app.

MyEventHandler handler = null; //Declare the handler

foreach (string pname in group)
{
  handler = getHandler(pname); //Get the handler
  if(handler == null)
  {                        
      throw new KeyNotFoundException("No user " + pname + " could be found");
  }
  //invoke the handler
  handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
}

So i get the handler and call BeginInvoke method. But before BeginInvoke gets called it goes to next iteration and the handler value gets changed. So the BeginInvoke is getting involved for this new handler.

Hope you get my point. So how can i eliminate this issue? I dont want to call sleep after BeginInvoke as i feel it is a loss of time.

Any ideas?

Update1 I'm pretty sure that the handler object gets changed before BeginInvoke() is called. I guess that the BeginInvoke takes some time to create a separate thread to call the other function.

Update2 This code is in a WCF service and the clients call a function which in turn makes use of this function. I've separate handlers stored in my server for each client. The WCF service has a duplex contract with separates sessions for the client. I see that after this function is executed same user is getting invoked twice. But i put a break point and debug it (which gives the BeginInvoke the necessary time to call the function) it works "PERFECTLY". I very sure i faced this problem in threading too where i create multiple threads in a loop. If the thread delegate has parameters a,b,c and if you change it at the beginning of the next iteration the same behavior occurs. I dono how many of you people have experienced this issue before. If i put a Sleep() or if i make a copy of the handler and invoke it using copy it'll work.

Update3

Okie, i've tested it now. I just added the Thread.Sleep() as follows.

chatTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
Thread.Sleep(500);

and it is working like a charm. Any thoughts?

Update 4

I've created a thread sample demonstrating the issue and i've uploaded it here. I hope a solution to this will resolve my issue too. Kindly check the sample.

解决方案

I can't see why this would happen - the code you posted cannot possibly reproduce the behaviour you describe. It's entirely reasonable that the BeginInvoke call might not actual do anything straight away, and that the next iteration might occur before you actually see that call do anything - since it will be queued for processing by a worker thread.

This doesn't mean that a different handler is being invoked - the handler to be invoked is captured as soon as BeginInvoke is called, so it won't matter if the local variable changes afterwards.

Also - why have you got the lock here? Unless multiple threads are doing this processing at the same time over the same enumerable (in which case why would you do that) I can't see any reason why you would lock.

I would also say that if you're judging this behaviour by what you see in the debugger, then you shouldn't worry - you'll get 'interesting' results from the debugger by doing this, and with the multiple threads in the mix it's important to switch threads in the 'Threads' debugger window.

The question is - does your program actually do what you expect? If so, but you're seeing this strange behaviour whilst debugging - then that's entirely normal.

As a few comments have stated - the code you posted can't be exactly what's producing the problem. If, for example, 'handler' is a local variable shared between multiple threads that then perform this iteration then, yes, you could get something like this. But a variable local to a method can only be modified (and indeed read) by the same thread that's currently in that method; the only exception to that rule being if the handler reference is then passed out to another threaded method as a ref.

这篇关于值在调用开始之前的迭代中被更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆