繁体   English   中英

值在调用开始之前的迭代中被更改

[英]Value getting changed in the iteration before the call begins

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

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调用它,它将起作用。

更新3

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

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

它的运作就像一种魅力。 有什么想法吗?

更新4

我创建了一个演示该问题的线程样本,并将其上传到此处 我希望对此的解决方案也能解决我的问题。 请检查样品。

好的,在您进行第四次编辑后,请提供一个示例,该示例肯定会出现问题,但没有寻求帮助的问题

您在问题中所说的是:

  • 我在委托变量上使用BeginInvoke,然后更改该变量,并以某种方式调用我的委托两次

您在发布的代码中展示的是:

  • 我在匿名方法中捕获了循环变量,并且以某种方式使用了错误的变量值

这些不是同样的问题!

您发布的代码行为不当的原因是,相关代码实际上看起来像这样:

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

然后,您将为每个线程捕获一个“新鲜”变量,该变量将保持不变。

因此,问题仍然存在。 这是您遇到的问题吗? 如果是这样,那么下次 不要 羞辱您不要简化问题 您是在浪费别人的时间,大部分都是自己的。 如果您在几分钟内发布了上述代码,那么您将在几分钟之内得到一个答案(或重复的问题,指向现有答案,那么多)。

如果这不是您遇到的问题,那么您仍然会遇到事件处理程序的问题,例如多次调用原始代码中的事件处理程序,请返回并生成一个更好的示例项目。

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

这并不意味着将调用其他处理程序-调用BeginInvoke时将立即捕获要调用的处理程序,因此本地变量随后是否更改都无关紧要

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

我还要说的是,如果您根据调试器中看到的内容来判断这种行为,那么您就不必担心-通过这样做以及混合使用多个线程,您将获得调试器的“有趣”结果在“线程”调试器窗口中切换线程很重要。

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

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

我认为您还有其他问题... handler.BeginInvoke在下一次迭代后无法调用,您仍然在同一线程中...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM