C# 远程处理后的服务器端清理

发布于 2024-08-22 04:47:27 字数 1954 浏览 10 评论 0原文

我有一个通过 C# 远程处理 (System.Runtime.Remoting) 运行的稍微简单的客户端/服务器解决方案。

然而,用于实际通信的 MarshalByRef 对象让我感到困扰。

在其构造函数中,它启动一个外部进程并添加 OutputDataReceived 事件处理程序。

每隔 2 秒,该进程就会将数据写入其标准输出,然后我在事件处理程序中检索并在其中使用。

现在我的问题是如何在这个过程之后进行清理 - 问题是,它无限期地运行,所以我必须调用 Kill() 来停止它。

我尝试在 MarshalByRef 对象的终结器中执行此操作,但这导致我的应用程序在尝试调用终结器时时不时地挂起。

远程处理被设置为单例,所以它应该是调用终结器的服务器端,所以坦率地说,我发现它有点奇怪,它不起作用。

生成该进程的类实际上是我的 MarshalByRef 对象的一个​​字段,但这实际上不应该改变太多。

该类还在 Linux 服务器上以单声道运行,并从工具 mpstat 中读取 CPU 负载。

这是困扰我的课程:

internal class CpuInfo
{
    private Regex parser = new Regex(@"\d{2}:\d{2}:\d{2}\s+(?<CpuID>\d{1,2}).*?(?<IdlePercentage>\d{1,2},\d{1,2})(\r|\n|$)", RegexOptions.Compiled | RegexOptions.Multiline);
    private Process proc;
    private IDictionary<int, long> cpuLoads;
    internal CpuInfo()
    {
        cpuLoads = new Dictionary<int, long>();
        proc = new Process();
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.CreateNoWindow = true;
        proc.StartInfo.Arguments = "-u -P ALL 2";
        proc.StartInfo.FileName = "mpstat";
        proc.StartInfo.RedirectStandardOutput = true;
        proc.EnableRaisingEvents = true;
        proc.OutputDataReceived += proc_OutputDataReceived;

        proc.Start();
        proc.BeginOutputReadLine();
    }

    void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        Match match = parser.Match(e.Data);
        if (match.Success)
        {
            int cpuID = int.Parse(match.Groups["CpuID"].Value);
            string idleValue = match.Groups["IdlePercentage"].Value.Replace(',', '.');
            decimal idle = decimal.Parse(idleValue, CultureInfo.InvariantCulture);
            cpuLoads[cpuID] = (long)((100m - idle) * 100);
        }
    }

    ~CpuInfo()
    {
        proc.OutputDataReceived -= proc_OutputDataReceived;
        proc.Kill();
    }
}

I have a somewhat simple Client/Server solution running over C# remoting (System.Runtime.Remoting).

The MarshalByRef object, which is used for the actual communication, however troubles me.

In its constructor it starts up an external process and adds the OutputDataReceived eventhandler.

Every 2 seconds the process will write data to its stdout, which I then retrieve in my eventhandler and use there.

Now my problem is how to cleanup after this process - the thing is, it runs indefinitely so I have to call Kill() on it to stop it.

I tried doing this in the MarshalByRef object's finalizer, however this caused my application to hang every now and then, when trying to call the finalizer.

The remoting is setup as a Singleton, so it should be the server side which calls the finalizer, so frankly I find it a bit odd it doesn't work.

The class that spawns the process is actually a field of my MarshalByRef object, but that really shouldn't change a lot.

Also the class is run in mono on a linux server, and reads out CPU load from the tool mpstat.

Here's the class which troubles me:

internal class CpuInfo
{
    private Regex parser = new Regex(@"\d{2}:\d{2}:\d{2}\s+(?<CpuID>\d{1,2}).*?(?<IdlePercentage>\d{1,2},\d{1,2})(\r|\n|$)", RegexOptions.Compiled | RegexOptions.Multiline);
    private Process proc;
    private IDictionary<int, long> cpuLoads;
    internal CpuInfo()
    {
        cpuLoads = new Dictionary<int, long>();
        proc = new Process();
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.CreateNoWindow = true;
        proc.StartInfo.Arguments = "-u -P ALL 2";
        proc.StartInfo.FileName = "mpstat";
        proc.StartInfo.RedirectStandardOutput = true;
        proc.EnableRaisingEvents = true;
        proc.OutputDataReceived += proc_OutputDataReceived;

        proc.Start();
        proc.BeginOutputReadLine();
    }

    void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        Match match = parser.Match(e.Data);
        if (match.Success)
        {
            int cpuID = int.Parse(match.Groups["CpuID"].Value);
            string idleValue = match.Groups["IdlePercentage"].Value.Replace(',', '.');
            decimal idle = decimal.Parse(idleValue, CultureInfo.InvariantCulture);
            cpuLoads[cpuID] = (long)((100m - idle) * 100);
        }
    }

    ~CpuInfo()
    {
        proc.OutputDataReceived -= proc_OutputDataReceived;
        proc.Kill();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千里故人稀 2024-08-29 04:47:27

现在我自己弄清楚了 - 我使用 RemoteServices.Marshal 服务器端和 RemoteServices.Connect 客户端。这样我的对象引用就存在于服务器端,并且我可以使用 IDisposable 很好地进行清理。

Figured it out myself now - I use RemoteServices.Marshal serverside and RemoteServices.Connect clientside. This way my object reference exists serverside, and I can use IDisposable to cleanup nicely.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文