C# 监听器线程上的 CPU 使用率高,休眠未命中断开连接

标签 c# multithreading winforms tcplistener tcpserver

我的连接处理程序在下面(这更多是为了个人实验而不是生产代码)

如果我不在 while 循环的任何地方添加 Thread.Sleep,它就会开始消耗 CPU。相反,如果我做 Sleep 来缓解无休止的 while-spam,我会错过断开连接的机会。CPU 会上升与正在运行的客户端/线程的数量成正比,因此导致高使用率的不是监听器本身,而是下面发布的实际客户端线程。任何人对如何解决这个问题有任何想法吗?

(我正在避免基于 await 的解决方案,因为我对 async/await 不够熟悉,线程方法对于这个相当小的项目工作正常)

我只是简单地搜索了 SO 以寻找解决方案,但没有注意到任何这个特定问题或提供了除了指导人们阅读异步/等待文章之外的解决方案,如果我确实错过了适用的答案,我深表歉意。

        private void HandleConnection(CancellationToken ct) {
        int recv = 0;
        byte[] buf = new byte[4096];
        Trace.WriteLine($"{_name} Connected");
        if (_ns.CanWrite && _client.Connected) {
            _ns.Write(Encoding.BigEndianUnicode.GetBytes("■WEL"), 0, Encoding.BigEndianUnicode.GetBytes("■WEL").Length);
            try {
                while (_client.Connected && !ct.IsCancellationRequested) {

                    while (!_ns.DataAvailable) { //first attempted solution
                        Thread.Sleep(100); // miss discon if i sleep here
                        }

                    if (ct.IsCancellationRequested) {
                        Trace.WriteLine($"{(string)this} thread aborting");
                        break;
                        }

                    buf = new byte[4096];

                    if (_client.Connected && _ns.DataAvailable) {

                        recv = _ns.Read(buf, 0, buf.Length);
                        } else {
                        recv = 0;
                        }

                    if (recv > 0) {

                        string r = Encoding.BigEndianUnicode.GetString(buf);
                        r = r.TrimEnd('\0');
                        if (String.IsNullOrEmpty(r) || String.IsNullOrWhiteSpace(r))
                            r = null; //need the !not version
                        else
                            if (ParseMsg(r))
                                break;
                        }

                    //Thread.Sleep(100); // also miss discon here too

                    }
                } catch (IOException ioe) { }
            Trace.WriteLine($"{_name} Disconnected");
            if (OnDisconnected != null)
                OnDisconnected(this);
            }
        }

最佳答案

通过套接字进行通信的正确方法是:

  1. 持续阅读。这些读取将阻塞,直到数据进入或直到套接字正常断开连接(可通过读取 0 字节完成的读取检测到)。
  2. 定期写作。 These writes are required to ensure the connection is still viable .

正确的线程方法要求每个连接两个线程。我不相信它比异步方法更简单。

附言如果您的代码使用 Connected,那么它就有一个错误。正确的解决方案永远不需要使用 Connected

关于C# 监听器线程上的 CPU 使用率高,休眠未命中断开连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43327534/

相关文章:

c++ - 具有两个线程的段错误逻辑

C++ future 并行处理

ios - Cocos2D 使用线程更新 UI

c# - 如何使文本框禁用但可选择

c# - 在 HPUX 上运行 C#

c# - 在 C# 中格式化日期时间

c# - DataGrid 保存按钮和 CanExecute

c# - C#中的VB.Net错误对象

winforms - Windows窗体中BackgroundImage的位置

c# - 如何定义跨多个表单使用的默认颜色/字体?