奇怪的if语句行为,零值为double [英] Strange if-statement behavior with zero value double

查看:148
本文介绍了奇怪的if语句行为,零值为double的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有人会向我解释,如果 this.oBalance.QouteBalance 的值在不明确的情况下被评估为小于零,那么这个值是否为真?请参阅下面的图片。



我在C#中比较双打时缺少一些基本的东西。



  public double QouteBalance {get;组; 

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



编辑: 如果这个代码很乱,那么代码就不行了,但是我不能编辑它,因为在很长的运行时间之后这是一个运行时错误,所以害怕不能重新创建它。异常消息是不正确的,只是提醒我自己。例外之后的代码是我在开始这个特定的运行之前忘记了注释。



编辑2:我正在建立并运行在发布模式



编辑3:赦免我的无知,但似乎我实际上是在多线程环境,因为这个代码被调用为更复杂的对象方法的一部分,该方法在定时器的ticks(事件)上执行。可能会要求定时器等待,直到其事件处理程序中的所有代码才能再次出现才能完成?



编辑4:这已经被确定为一个多线程问题;我将尝试给出更广泛的上下文来获得优化的解决方案。



我有一个定时器对象,它执行每个刻度上的以下内容:


  1. 运行后台工作人员从文件读取数据

  2. 当背景工作完成从文件读取数据,提高
    事件

  3. 在事件处理程序中,运行调用下面方法
    (在图像中)的对象代码和其他多个例程,包括GUI更新。

我想这个问题可以通过使用定时器Tick事件来读取文件,但是改变这个将破坏我的代码的其他部分。

解决方案

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



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



编辑:回答您的修改:



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



我使用Interlocked类指定的原因,而不是使用共享变量,原因在于你一次从多个线程访问。如果你不使用联锁,你可以得到两个勾号,既检查价值,并得到一个答案,他们可以继续翻转标志以保持他人。您将遇到同样的问题。



更为传统的同步访问共享数据成员的方法是锁定,但是您将很快遇到刻录事件触发的问题太快了,他们会开始备份你。



编辑2 :回答你的问题,共享变量在多个线程上,这真的取决于你在做什么具体。我们有一个非常小的窗口,你的应用程序正在做什么,我将从所有的意见和答案中拼凑出来,希望它将通知您的设计选择。



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

public void Handle_Tick(...)
{
//检查我们是否已经很忙。如果
//我们已经在处理,我们不需要泵工作。
if(IsBusy)
return;

try
{
IsBusy = true;

//执行你的工作
}
finally
{
IsBusy = false;
}
}

在这种情况下,IsBusy可能是一个波动的bool,可以使用 Interlocked 命名空间方法,它可能是一个锁定等等。你所选择的取决于你。



如果这个前提是不正确的,你其实必须做使用定时器的每个刻度,这将不适用于您。你正在扔掉你忙的时候进来的蜱虫。如果你想保持每一个滴答声,你需要实现一个同步的队列。如果你的频率很高,你必须要小心,最终会溢出。


Would anyone care to explain to me how the value of this.oBalance.QouteBalance is evaluated to be true for being less than zero when it clearly isn't? Please see image below.

Am I missing something fundamental when it comes to comparing doubles in C#??

public double QouteBalance { get; set; }

UpdateBalance_PositionOpenned() is not being called in a loop, but is being called as part of a more complex event driven procedure that runs on the ticks of a timer (order of milliseconds)

EDIT: Pardon the code if it's messy but I couldn't edit it as this was a run-time error after quite a long run-time so was afraid wouldn't be able to recreate it. The Exception message is not correct and just a reminder for myself. The code after the exception is code I forgot to comment out before starting this particular run.

EDIT 2: I am building and running in Release Mode.

EDIT 3: Pardon my ignorance, but it would seem that I am in fact running in a multi-threaded environment since this code is being called as part of a more complex object method that gets executed on the ticks (Events) of a timer. Would it possible to ask the timer to wait until all code inside its event handler has finished before it can tick again?

EDIT 4: Since this has been established to be a multi-threading issue; I will try to give wider context to arrive at an optimized solution.

I have a Timer object, which executes the following on every tick:

  1. Run a background worker to read data from file
  2. When background worker finishes reading data from file, raise an Event
  3. In the event handler, run object code that calls the method below (in the image) and other multiple routines, including GUI updates.

I suppose this problem can be avoided by using the timer Tick events to read the from file but changing this will break other parts of my code.

解决方案

You're accessing shared variables from multiple threads. It's probably a race condition where one thread has thrown the error but by the time the debugger has caught and attached, the variable's value has changed.

You would need to look at implementing synchronizing logic like locking around the shared variables, etc.

Edit: To answer your edit:

You can't really tell the timer to not tick (well you can, but then you're starting and stopping and even after calling Stop you might still receive a few more events depending on how fast they are being dispatched). That said, you could look at Interlocked namespace and use it to set and clear and IsBusy flag. If your tick method fires and sees you're already working, it just sits out that round and waits for a future tick to handle work. I wouldn't say it's a great paradigm but it's an option.

The reason I specify using the Interlocked class versus just using a shared variable against comes down to the fact you're access from multiple threads at once. If you're not using Interlocked, you could get two ticks both checking the value and getting an answer they can proceed before they've flipped the flag to keep others out. You'd hit the same problem.

The more traditional way of synchronizing access to shared data member is with locking but you'll quickly run into problems with the tick events firing too quickly and they'll start to back up on you.

Edit 2: To answer your question about an approach to synchronizing the data with shared variables on multiple threads, it really depends on what you're doing specifically. We have a very small window into what your application is doing so I'm going to piece this together from all the comments and answers in hopes it will inform your design choice.

What follows is pseudo-code. This is based on a question you asked which suggests you don't need to do work on every tick. The tick itself isn't important, it just needs to keep coming in. Based on that premise, we can use a flagging system to check if you're busy.

...
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;
    }
}

In this case, IsBusy could be a volatile bool, it could be accessed with Interlocked namespace methods, it could be a locking, etc. What you choose is up to you.

If this premise is incorrect and you do in fact have to do work with every tick of the timer, this won't work for you. You're throwing away ticks that come in when you're busy. You'd need to implement a synchronized queue if you wanted to keep hold of every tick that came in. If your frequency is high, you'll have to be careful as you'll eventually overflow.

这篇关于奇怪的if语句行为,零值为double的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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