我有一个与外部.exe对话的课程。该类有一堆类似的方法;他们调用.exe的函数,等待响应,然后返回true或false。
响应以更改此类字段值的事件形式出现。
简化代码:
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;
}
}
其他方法使用相同的call-wait-loop-return结构。
我的目标是制作一个方法来等待我这样做:
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;
}
然后每种方法都可以:
runtime.DoSomething();
return WaitReferenceEqualsValue<someType>(ref someField, someSuccessfulValue);
但是,当我用这个方法调用替换wait-loop时,即使作为引用传入,“connected”字段始终保持不变。
知道这里发生了什么,以及如何获得所需的功能?
提前致谢。
编辑:
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:
private static void OnConnect(object sender, Events.OnConnectArgs e)
{
if (e != null && e.success)
{
lock (typeof(Manager))
{
connected = true;
}
}
}
答案 0 :(得分:3)
虽然您从多个线程访问它并且其中一个正在编写,但您在该字段上没有进行任何同步。这是一场比赛(也不例外!即使它看起来很安全,这个 也是一场比赛。这不安全。)。
可能JIT注册了它,这是一个常见的优化。它永远不会从内存中读取,总是从寄存器中读取。添加同步(例如锁定,或互锁或易失性方法)。
您对ref的使用是正确的。
答案 1 :(得分:2)
代码的问题本质上是编译器优化。 Fo优化目的编译器(或jits)必须采用相当多的单线程视图。然后编译器/ jit会注意到你根本没有触及代码中的reference
,因此它可以在循环外移动比较。它是免费的,因为你基本上创建了一个竞争条件(没有同步/原子访问)。
修复它可能涉及使用同步机制或将volatile
说明符添加到reference
,从而告诉编译器/ jit,可以从方法外部更改变量。