Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 被父线程中的变量求值弄糊涂了_C#_Multithreading - Fatal编程技术网

C# 被父线程中的变量求值弄糊涂了

C# 被父线程中的变量求值弄糊涂了,c#,multithreading,C#,Multithreading,我在一家在外地有多家店铺的公司工作。当我们需要连接到商店POS系统时,我们需要先连接到他们的VPN。我正在开发一个GUI来帮助简化流程。我让它工作得很好,但我偶然发现了一些我不理解的行为 当程序连接到VPN时,它将启动OpenVPN控制台程序,等待程序询问用户名和密码,然后监视程序输出,以检测连接是否成功,跟踪错误消息或何时由于不活动而断开连接 在我的开发机器上,我得到了一致而准确的结果。当我在一台实际机器上运行它时,它无法正确检测VPN连接何时成功。例如 这是监视OpenVPN输出的代码 va

我在一家在外地有多家店铺的公司工作。当我们需要连接到商店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)

所以我不明白的是,如果我注释掉Console.WriteLine(--message--),那么这些变量在while(!\u vpnConnected&&u trackOpenVpnOutput)循环中的计算似乎不正确


现在,我将把调试控制台.WriteLine留在那里,因为它可以工作,但我想了解为什么我会看到这种行为,并希望了解处理这种情况的正确方法。

我猜
\u vpnConnected
\u trackOpenVpnOutput
都是
bool
字段

您偶然发现的是多线程更改可见性,此外,编译器能够在假设可见性为零的情况下进行优化。编译器不知道其他线程能够更改这些变量,因此可以自由地优化重复读取

您需要告诉它不要优化这些读取——每次都要重新读取变量。您可以通过将变量标记为
volatile
,或使用
volatile来执行此操作。请阅读:

while (!Volatile.Read(ref _vpnConnected)
     && Volatile.Read(ref _trackOpenVpnOutput))

考虑在DLL上使用ILDASM,看看IL是否有差异。当取消Console语句时,可能会进行优化。在问题的此处张贴任何IL差异。听起来,至少在
\u vpn connected
\u trackOpenVpnOutput
周围需要某种内存屏障。您可以尝试声明它们,但不查看外部代码。我不确定这是否足够。您是否在开发计算机上测试了发布版本?您是对的,它们都是布尔值。我很抱歉没有说明这一点。我将这些变量的声明更改为volatile,它工作正常。非常感谢你提供的信息。我要去读一下volatile关键字,这样我就能更好地理解它了!推荐阅读有关本书的内容。
while (!Volatile.Read(ref _vpnConnected)
     && Volatile.Read(ref _trackOpenVpnOutput))