对父线程中的变量计算感到困惑

本文关键字:计算 变量 线程 | 更新日期: 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))