对父线程中的变量计算感到困惑
本文关键字:计算 变量 线程 | 更新日期: 2023-09-27 18:34:56
我在一家在现场拥有多家商店的公司工作。当我们需要连接到商店POS系统时,我们需要先连接到他们的VPN。我正在开发一个 GUI 来帮助简化流程。我让它工作得很好,但我偶然发现了一些我不理解的行为。
当程序连接到VPN时,它将触发OpenVPN控制台程序,等待程序询问用户名和密码,然后监视程序输出以检测连接是否成功,跟踪错误消息或何时由于不活动而导致连接断开。
在我的开发机器上,我得到了一致且准确的结果。当我在其中一台实际机器上运行它时,它无法正确检测 VPN 连接何时成功。例如。。。
这是监视OpenVPN输出的代码。
var outputProcessingThread = new Thread(() =>
{
while (_trackOpenVpnOutput)
{
var buffer = new byte[256];
IAsyncResult ar = _vpnProcess.StandardOutput.BaseStream.BeginRead(buffer, 0, 256, null, null);
ar.AsyncWaitHandle.WaitOne();
var bytesRead = _vpnProcess.StandardOutput.BaseStream.EndRead(ar);
if (bytesRead > 0)
{
var outputString = Encoding.ASCII.GetString(buffer, 0, bytesRead);
RaiseDebugVpnMessageEvent(new VpnMessageEventArgs(outputString, VpnMessageType.Info));
if (outputString.Contains("Initialization Sequence Completed With Errors"))
{
_trackOpenVpnOutput = false;
_vpnConnected = false;
const string message = "Unable to connect to VPN: Errors in Initialization Sequence";
RaiseVpnMessageEvent(new VpnMessageEventArgs(message, VpnMessageType.Error));
return;
}
if (outputString.Contains("Initialization Sequence Completed"))
{
RaiseVpnMessageEvent(new VpnMessageEventArgs(String.Format("Connected to #{0}'s VPN.", storeNumber), VpnMessageType.Info));
_vpnConnected = true;
}
else if (outputString.Contains("Inactivity timeout"))
{
RaiseVpnMessageEvent(new VpnMessageEventArgs("Inactivity timeout. Disconnected from VPN.", VpnMessageType.Warning));
_vpnConnected = false;
_trackOpenVpnOutput = false;
return;
}
else if (outputString.Contains("TLS Error"))
{
RaiseVpnMessageEvent(new VpnMessageEventArgs("Unable to connect to VPN: TLS Error.", VpnMessageType.Error));
_vpnConnected = false;
_trackOpenVpnOutput = false;
return;
}
}
}
});
然后在我触发该线程后,我用这个检查它(等到 VPN 已连接或它们出错并且输出处理线程_trackOpenVpnOutput更改为 false(......
while (!_vpnConnected && _trackOpenVpnOutput)
{
Console.WriteLine("VPN Connected: {0} 't'tTracking OpenVPN: {1}", _vpnConnected, _trackOpenVpnOutput);
}
所以我不明白的部分是,如果我注释掉 Console.WriteLine(--message--(,那么这些变量似乎在 while (!_vpnConnected &&_trackOpenVpnOutput( 循环中没有得到正确的评估。
现在,我将把调试 Console.WriteLine 留在那里,因为它有效,但我想了解为什么我会看到这种行为,并希望了解处理此类情况的正确方法。
我猜_vpnConnected
_trackOpenVpnOutput
都是bool
字段。
您偶然发现的是多线程更改可见性,此外,编译器能够在零可见性的情况下进行优化。编译器不知道另一个线程能够更改这些变量,因此可以自由地优化重复读取。
你需要告诉它不要优化这些读取 - 每次都重新读取变量。 您可以通过将变量标记为 volatile
或使用 Volatile.Read
来执行此操作:
while (!Volatile.Read(ref _vpnConnected)
&& Volatile.Read(ref _trackOpenVpnOutput))