我的应用程序中有以下代码。
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);
}
所以我得到了处理程序并调用了BeginInvoke
方法。但在BeginInvoke
被调用之前,它会转到下一次迭代,并且处理程序值会发生变化。因此BeginInvoke
涉及这个新的处理程序。
希望你明白我的观点。那我怎么能消除这个问题呢?我不想在BeginInvoke
之后打电话给睡觉,因为我觉得这是在浪费时间。
有什么想法吗?
UPDATE1 我很确定在调用BeginInvoke()之前处理程序对象会被更改。我猜BeginInvoke需要一些时间来创建一个单独的线程来调用另一个函数。
UPDATE2 此代码位于WCF服务中,客户端调用一个函数,该函数依次使用此函数。我为每个客户端分别存储在我的服务器中的处理程序。 WCF服务具有双工合同,为客户端分隔会话。我看到执行此函数后,同一个用户被调用两次。但我设置了一个断点并调试它(这给BeginInvoke提供了调用函数所需的时间)它“完美地”工作。我非常确定我在线程中也遇到了这个问题,我在循环中创建了多个线程。如果线程委托具有参数a,b,c,并且如果在下一次迭代开始时更改它,则会发生相同的行为。我之前有多少人遇到过这个问题。如果我放入一个Sleep()或者如果我复制一个处理程序并使用copy调用它,那么它将起作用。
UPDATE3
好吧,我现在已经测试过了。我刚刚添加了Thread.Sleep(),如下所示。chatTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
Thread.Sleep(500);
它的工作就像一个魅力。有什么想法吗?
更新4
我创建了一个演示问题的线程示例和i've uploaded it here。我希望解决这个问题也能解决我的问题。请检查样品。
答案 0 :(得分:5)
好的,在您进行第四次编辑后,您向我们提供了一个示例,该示例表明存在问题,当然不是您要求帮助的问题。
你在问题中说的是:
您在发布的代码中展示的是:
这些不是同样的问题!
您发布的代码行为不当的原因是所涉及的代码实际上看起来像这样:
int i;
for (i = 0; i < 10; i++)
... create delegate, capture i, spawn thread
这里你为所有线程捕获相同的变量。如果一个线程在循环更改变量之前没有开始执行,那么是的,您将看到该变量的“不正确的值”。
但是,如果你改变这样的代码:
for (int i = 0; i < 10; i++)
{
int j = i;
ThreadStart threadStartObj = new ThreadStart(
delegate { PrintValueThreadFunction(j, j); });
^
|
+-- use j instead of i here
然后,您将为每个线程捕获一个“新”变量,该变量不会被更改。
所以,问题仍然存在。这是你遇到的问题吗?如果是这样,那么羞辱你,下次不简化问题。你在浪费人们的时间,尤其是你自己的时间。如果您在上面发布了类似上面的代码,那么您可能会在几分钟内找到答案(或者是一个重复的问题,指向现有的答案,有很多)。
如果这不是您遇到的问题,那么您仍然遇到一个事件处理程序的问题,就像在多次调用的原始代码中一样,返回并生成一个更好的示例项目。
答案 1 :(得分:1)
我不明白为什么会发生这种情况 - 您发布的代码无法重现您描述的行为。完全合理的是,BeginInvoke调用可能不会立即执行任何操作,并且在您实际看到该调用执行任何操作之前可能会发生下一次迭代 - 因为它将排队等待工作线程处理。
这并不意味着调用了一个不同的处理程序 - 一旦调用了BeginInvoke就会捕获要调用的处理程序,因此后来本地变量是否会发生变化无关紧要 强>
另外 - 为什么你在这里锁?除非多个线程在同一个可枚举的同时进行此处理(在这种情况下你为什么要这样做),我看不出你为什么会锁定的任何理由。
我还会说,如果您通过调试器中看到的内容来判断这种行为,那么您不必担心 - 通过执行此操作,以及使用多个线程,您将从调试器获得“有趣”的结果在混合中,在“线程”调试器窗口中切换线程非常重要。
问题是 - 您的计划实际上是否符合您的期望?如果是这样,但你在调试时会看到这种奇怪的行为 - 那就完全正常了。
正如一些评论所说 - 您发布的代码不能正是产生问题的原因。例如,如果'handler'是在多个线程之间共享的局部变量然后执行此迭代,那么,是的,你可以得到这样的东西。但是方法的局部变量只能由当前在该方法中的相同线程修改(实际上是读取);该规则的唯一例外是,handler
引用随后作为ref
传递给另一个线程方法。
答案 2 :(得分:0)
我认为你还有其他一些问题......在下次迭代后无法调用handler.BeginInvoke,你仍然在同一个线程中......