none
release模式运行时,在某种条件下udpClient receive线程好像没有关闭成功 RRS feed

  • 问题

  • 使用UdpClient类进行了udp通讯。

    开启了一个线程用于专门接收消息

    当我stop的时候,我会先关闭线程再关闭释放socket,但是接收线程好像没有关闭成功,具体现象看下面截图更好。

    代码如下:

    开启的接收线程:

    public bool Start(string ip)
            {
                if (IPAddress.TryParse(ip, out IPAddress address))
                    hostPoint = new IPEndPoint(address, 8888);//服务器端套接字,客户端发送数据到此套接字 192.168.8.172
                else
                    return false;
    
                client = new UdpClient(8901);//客户端使用8901端口发送数据 
                receivePoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);//s收到的服务器端的套接字
    
                client.Client.ReceiveBufferSize = (1024 * 1024);
    
                if (null == rcvthread)
                    rcvthread = new Thread(SocketRcvProc); //创建接收线程
                rcvthread.IsBackground = true;
                rcvthread.Start(); //启动线程
    
                if (0 < SubscirbeProcessMsg())
                    return true;
                return false;
            }
    
    void SocketRcvProc()
            {
                UInt32 pktSn = 0;
                UInt32 lastMsgSn = 0;
                UInt32 rcvdLen = 0;
                Msg msg = new Msg(MAX_MSG_LEN);
    
                while (true)
                {
                    try
                    {
                        byte[] rcvData = client.Receive(ref receivePoint);
    
                        if (0 == RecvOnePkt(msg, ref pktSn, ref lastMsgSn, ref rcvdLen, new Packet(rcvData)))
                        {
                            foreach (CMD_PROCESS_MAP proc in procList)
                                if (msg.type == proc.type)
                                    proc.process(msg);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }
            }

    这是我stop时候的操作:
    public bool Stop()
            {
                if (null != client)
                {
                    client.Close();
                    client.Dispose();
                    client = null;
                    Console.WriteLine("client close");
                }
                hostPoint = null;
                receivePoint = null;
    
                if (null != rcvthread)
                {
                    rcvthread.Abort();
                    rcvthread = null;
                    Console.WriteLine("recvthread close");
                }
                
                Console.WriteLine("point close");
                return true;
            }

    当我进行stop操作的时候会出现下面的情况:

    就感觉线程没有关闭一样,并且那个socket还一直在receive。

    因为当我再次重新start的时候,我会出现丢包的现象。

    上述所有现象都是在release模式才发生的且是必现。debug模式从未遇到以上现象。

    我也做过以下的验证:

    1、进入catch后,直接break,肯定可以解决此问题。

    2、直接撤掉try..catch,没有了上述现象-----但是无法解释为什么

    3、保留try..catch,在try的上面随意加一行代码,例如Console.WriteLine("=========receive==========")

         也不会出现上述现象------但我还是无法理解为什么???

    欢迎大家留言讨论!!!

    2019年11月22日 5:39

答案

  • Hi heater,
    我查看了你的代码,没有发现你在何处调用了stop()方法。使用Thread.Abort()方法并不会立即终止线程,而且Abort()方法是通过抛出异常来终止线程,存在很多不确定因素。比较好的做法是在启动的线程中加信号灯,当想要终止线程执行时就更改信号灯的状态,启动的线程当读到信号灯状态改变后自己结束代码的执行。
    关于如何加信号灯,你可以参考这个文章。

    C#如何优雅的结束一个线程

    Best Regards,
    Daniel Zhang

    Note: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; Therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet.


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年11月22日 9:25
  • 不过Abort方法被调用后,目标线程可能并不是马上就终止了。因为只要目标线程正在调用非托管的代码而且还没有返回的话,该线程就不会立即终止。而如果目标线程在调用非托管的代码而且陷入了一个死循环的话,该目标线程就根本不会终止。

    --------非常感谢,已经找到原因啦。stop()和start()方法都是点击按钮调用的。但是为什么在debug模式下不会出现这种原因,还有我上面做的验证,还是有点不理解。

    • 已标记为答案 heater 2019年12月2日 10:53
    2019年11月25日 2:35

全部回复

  • Hi heater,
    我查看了你的代码,没有发现你在何处调用了stop()方法。使用Thread.Abort()方法并不会立即终止线程,而且Abort()方法是通过抛出异常来终止线程,存在很多不确定因素。比较好的做法是在启动的线程中加信号灯,当想要终止线程执行时就更改信号灯的状态,启动的线程当读到信号灯状态改变后自己结束代码的执行。
    关于如何加信号灯,你可以参考这个文章。

    C#如何优雅的结束一个线程

    Best Regards,
    Daniel Zhang

    Note: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; Therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet.


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年11月22日 9:25
  • 不过Abort方法被调用后,目标线程可能并不是马上就终止了。因为只要目标线程正在调用非托管的代码而且还没有返回的话,该线程就不会立即终止。而如果目标线程在调用非托管的代码而且陷入了一个死循环的话,该目标线程就根本不会终止。

    --------非常感谢,已经找到原因啦。stop()和start()方法都是点击按钮调用的。但是为什么在debug模式下不会出现这种原因,还有我上面做的验证,还是有点不理解。

    • 已标记为答案 heater 2019年12月2日 10:53
    2019年11月25日 2:35
  • Hi heater,
    根据我的了解,在Debug版本中,可以使用单步执行、跟踪等功能,但其生成的可执行文件比较大,代码运行比较慢。Release版本 就是发行版本,其运行速度较快,可执行文件较小,所以可能存在由于Debug模式下运行时间较长,线程已销毁。
    关于Debug和Release的区别, 你可以参考以下这篇文章。
    VS中Debug模式和Release模式的区别
    Best Regards,
    Daniel Zhang

    Note: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; Therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet.


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年11月28日 5:50