简体   繁体   English

C#“参考”不做我认为应该做的

[英]C# “ref” not Doing what I Think it Should

I have a class that talks to an external .exe. 我有一个与外部.exe对话的类。 The class has a bunch of similar methods; 这个类有很多类似的方法。 they call a function of the .exe, wait for response, and then return true or false. 他们调用.exe函数,等待响应,然后返回true或false。

The response comes in the form of events that change the values of fields of this class. 响应以事件的形式出现,这些事件会更改此类的字段的值。

Simplified code: 简化代码:

class Manager
{
    private static bool connected = false;

    public static bool Connect()
    {
        runtime.Connect();

        int secondsWaited = 0;

        while (!connected)
        {
            Thread.Sleep(1000);

            if (secondsWaited++ == 10)
            {
                return false;
            }
        }
        return true;
    }
}

The other methods use the same call-wait-loop-return structure. 其他方法使用相同的call-wait-loop-return结构。

My goal is to make a single method to do this waiting for me, like so: 我的目标是制定一个单一的方法来等待我,例如:

private static bool WaitReferenceEqualsValue<T>(ref T reference, T value)
{
    int secondsWaited = 0;

    while (!reference.Equals(value))
    {
        Thread.Sleep(1000);

        if (secondsWaited++ == 10)
        {
            return false;
        }
    }
    return true;
}

Then each method would do: 然后每种方法都可以:

runtime.DoSomething();

return WaitReferenceEqualsValue<someType>(ref someField, someSuccessfulValue);

However, when I replace the wait-loop with this method call, the field "connected", even though passed in as a reference, always stays the same. 但是,当我用此方法调用替换wait-loop时,即使作为引用传入,“ connected”字段也始终保持不变。

Any idea what's going on here, and how to get the desired functionality? 知道这里发生了什么以及如何获得所需的功能吗?

Thanks in advance. 提前致谢。

EDIT: 编辑:

public static bool Connect()
{
    ...
    runtime.Connect();

    // this code works
    /*int secondsWaited = 0;

    while (connected != true)
    {
        Thread.Sleep(1000);

        if (secondsWaited++ == 10)
        {
            return false;
        }
    }*/

    // this somehow blocks OnConnect from firing, so connected never gets set to true
    lock (typeof(SkypeKitManager))
    {
        WaitReferenceEqualsValue<bool>(ref connected, true);
    }
    ...
}

OnConnect: 的onConnect:

private static void OnConnect(object sender, Events.OnConnectArgs e)
{
    if (e != null && e.success)
    {
        lock (typeof(Manager))
        {
            connected = true;
        }
    }
}

You're not doing any synchronization on that field although you access it from multiple threads and one of them is writing. 尽管您从多个线程访问该字段,但其中一个正在写,但您并未对该字段进行任何同步。 This is a race (no exception! this is a race even if it looks safe. It isn't safe.). 这是一场比赛(也不例外!即使看起来很安全,这也是一场比赛。这不是安全的。)

Probably the JIT enregistered it which is a common optimization. JIT可能会注册它,这是常见的优化。 It just never gets read from memory, always from a register. 它永远不会从内存中读取,总是从寄存器中读取。 Add synchronization (for example a lock, or Interlocked or Volatile methods). 添加同步(例如,锁定,互锁或易失方法)。

Your usage of ref is correct. 您对ref的使用是正确的。

The problem with your code is essentially compiler optimization. 您的代码的问题本质上是编译器优化。 Fo optimization purpose compilers (or jits) necessarily take a pretty much single threaded view. 用于优化目的的编译器(或jit)必须采用几乎单线程的视图。 The compiler/jit will then notice that you don't touch reference in your code at all, therefore it can move the comparison outside the loop. 然后,编译器/ jit将注意到您根本不触摸代码中的reference ,因此它可以将比较移到循环外。 It is free to do so, since you basically create a race condition (no synchronization/atomic accesses). 这样做是免费的,因为您基本上创建了竞争条件(无同步/原子访问)。

Fixing it could either involve using synchronization mechanisms or add the volatile specifier to reference , thus telling the compiler/jit, that the variable can be changed from outside the method. 修复它可能涉及使用同步机制,或者将volatile说明符添加到reference ,从而告诉编译器/ jit,可以从方法外部更改变量。

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

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