奇怪的if语句行为,零值为double

时间:2014-03-04 20:12:42

标签: c# .net double

是否有人愿意向我解释this.oBalance.QouteBalance的值如何被评估为真实,因为它显然不是零?请看下面的图片。

在比较C#中的双打时,我是否遗漏了一些基本的东西

enter image description here

public double QouteBalance { get; set; }

UpdateBalance_PositionOpenned()未在循环中调用,但是作为更复杂的事件驱动过程的一部分被调用,该过程在计时器的刻度上运行(毫秒级)

编辑:请原谅代码,如果它很乱,但我无法编辑它,因为这是一个运行时错误,经过相当长的运行时间,所以害怕无法重新创建它。异常消息不正确,只是我自己的提醒。异常之后的代码是我在开始此特定运行之前忘记注释掉的代码。

编辑2:我正在发布模式中构建并运行。

编辑3:请原谅我的无知,但似乎我实际上是在多线程环境中运行,因为此代码被调用为更复杂的对象方法的一部分,该方法被执行在计时器的刻度(事件)上。是否有可能要求计时器等到其事件处理程序中的所有代码都完成才能再次打勾?

编辑4:由于这已被确定为多线程问题;我将尝试提供更广泛的背景,以达到优化的解决方案。

我有一个Timer对象,它会在每个刻度上执行以下操作:

  1. 运行后台工作程序以从文件中读取数据
  2. 当后台工作人员完成从文件中读取数据时,请提高 事件
  3. 在事件处理程序中,运行调用以下方法的对象代码 (在图像中)和其他多个例程,包括GUI更新。
  4. 我认为通过使用计时器Tick事件来读取文件可以避免这个问题,但是更改它会破坏我代码的其他部分。

3 个答案:

答案 0 :(得分:2)

您正在从多个线程访问共享变量。这可能是一个竞争条件,其中一个线程抛出了错误,但是当调试器捕获并附加时,变量的值已经改变。

您需要查看实现同步逻辑,例如锁定共享变量等等。

修改:要回答您的修改:

您真的不能告诉计时器不打勾(当然你可以,但你要启动和停止,甚至呼吁停止后仍可能收到取决于他们正在派出多快多了一些事件)。也就是说,您可以查看Interlocked命名空间并使用它来设置和清除IsBusy标志。如果您的tick方法触发并且看到您已经在工作,那么它只是坐在那一轮并等待未来的滴答来处理工作。我不会说这是一个很好的范例,但它是一个选择。

我使用Interlocked类指定的原因与仅使用共享变量的原因归结为您可以同时从多个线程进行访问。如果你没有使用Interlocked,你可以得到两个滴答,既检查值又得到一个答案,他们可以在他们翻转旗帜以防止其他人离开之前继续。你遇到了同样的问题。

同步访问共享数据成员的更传统的方法是使用锁定,但是你很快就会遇到问题,因为tick事件发生得太快,他们会开始备份你。

编辑2 :要回答有关在多个线程上将数据与共享变量同步的方法的问题,这实际上取决于您具体做什么。我们有一个非常小的窗口可以显示您的应用程序正在执行的操作,因此我将从所有注释和答案中将其拼凑在一起,希望它能够为您的设计选择提供信息。

以下是伪代码。这是基于您提出的一个问题,这个问题表明您不需要在每个刻度线上进行操作。滴答本身并不重要,它只需要继续进入。基于这个前提,我们可以使用标记系统来检查您是否正忙。

...
Timer.Start(Handle_Tick)
...

public void Handle_Tick(...)
{
    //Check to see if we're already busy. We don't need to "pump" the work if
    //we're already processing.
    if (IsBusy)
        return;

    try
    {
        IsBusy = true;

        //Perform your work
    }
    finally
    {
        IsBusy = false;
    }
}

在这种情况下,IsBusy可能是挥发性布尔,它可以用Interlocked命名空间的方法来访问,也可能是一个锁定,等你选择什么,完全由你。

如果这个前提是不正确的,并且你确实必须对计时器的每个滴答工作,这对你不起作用。当你忙的时候,你正在扔掉进来的虱子。如果你想保留每一个滴答声,你需要实现一个同步队列。如果你的频率很高,你必须要小心,因为你最终会溢出。

答案 1 :(得分:1)

这不是一个真正的答案,但是:

  

UpdateBalance_PositionOpenned()没有在循环中调用,但是   被称为更复杂的事件驱动程序的一部分   在计时器的刻度上运行(毫秒级)

见:

  

多线程? - abatishchev 30分钟前

毫秒级的紧定时器驱动的事件循环可能具有线程的所有问题,并且几乎完全不可能使用逐步调试器进行故障排除。东西发生的速度比你可以击中'F10'的速度快。更不用说,您在每个事件周期中从不同的线程访问变量,但是看不到同步。

答案 2 :(得分:0)

不是一个完整的答案,但评论太多了 这就是我如何编写防御性的代码 本地范围导致意外情况减少 它使代码更容易调试和测试

public void updateBalance(double amount, double fee, out double balance)
{
    try
    {
        balance = amount * (1.0 + fee);
        if (balance < 0.0) balance = 0.0;
    }
    catch (Exception Ex)
    {
        System.Diagnostics.Debug.WriteLine(Ex.Message);
        throw Ex;
    }
}

复制值类型,因此即使在方法执行方法中的金额值时,输入变量的金额也不会改变。

现在没有锁的失衡是一个不同的故事。