【问题标题】:nested Threads with c#使用 c# 嵌套线程
【发布时间】:2011-05-02 21:40:50
【问题描述】:

嗨,我对一般线程非常陌生。 我正在用 C# 开发类似蓝牙聊天的东西。 主要形式有 2 种可能性 1.更新BT设备列表并连接设备(工作正常) 2.监听连接到自己BT芯片的设备。

用于测试BT功能被禁用。

对于#2,我在加载表单后创建了一个线程。

    private void MainForm_Load(object sender, EventArgs e)
    {           
        incomingConnectionThread = new Thread(checkForConnection);
        incomingConnectionThread.Start();
    }

    public void checkForConnection()
    {
        while (listening) //boolean which is always true
        {
            if (cargui == null)
            {
                cargui = new sendReceiveForm(null);
                cargui.ShowDialog();
            }
        }
    }

因为监听总是正确的,所以会创建并显示一个新的表单(新的 sendReceiveForm)。

新表单包含另一个线程,该线程在新表单加载后执行 并且有一个循环来检查流是否收到信息。

    private void CarGui_Load(object sender, EventArgs e)
    {
        thread = new Thread(receiveData);
        thread.Start();
    }

    private void receiveData()
    {
        while (listening)
        {
            try
            {
                if (stream.ReadByte() != -1)
                {
                    if (rtfReceiveWindow.InvokeRequired)
                    {
                        rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
                    }

                    else
                    {
                        rtfReceiveWindow.Text += stream.ReadByte().ToString();
                    }
                }                 
            }
            catch
            {
            }

        }
    }

第二种形式的流是来自一个简单的 .txt streamReader 的流,具有 1 位数字。 第二个线程陷入无限循环(或看起来如此)并且应用程序崩溃。 我不知道问题出在哪里,也不知道如何解决。

//编辑

将方法更新为:

private void receiveData()
    {
        while (listening)
        {               
            if (stream.ReadByte() != -1)
            {
                if (rtfReceiveWindow.InvokeRequired)
                {
                    rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
                }

                else
                {
                    rtfReceiveWindow.Text += stream.ReadByte().ToString();
                }
            }                  
        }
    }

但没有区别

//EDIT2

问题是它工作正常,直到启动 2 线程。 如果我评论 2 线程的开头,则创建表单并且似乎工作正常。

【问题讨论】:

    标签: c# multithreading bluetooth chat


    【解决方案1】:

    我很确定这个子句隐藏了这个问题:

        catch
        {
        }
    

    删除它,因为它会捕获所有异常并且什么都不做。删除后再次以调试模式运行,您将看到实际错误。看看here

    【讨论】:

    • 谢谢 4 您的回复。我删除了 try/catch,但遗憾的是我没有任何区别。一个有趣的事实可能是 ne 表单显示为“未完成”状态。表单元素看起来像“占位符”。
    • @Alex 请更新问题,无法读取 cmets 中的代码
    • @Alex 好吧,你说应用程序在 debug 模式下崩溃,而 Visual Studio 没有显示任何异常?
    • 它实际上并不是“崩溃”,而是一个无限循环。程序总是从 while 跳转到 if(在线程中)并再次返回,直到我停止执行
    • @Alex 但这是您的应用程序所做的!它在无限循环中运行。为什么它不应该“从while跳到if”?如果你不想让它冻结,你可以在两者之间添加Thread.Sleep
    【解决方案2】:

    你的receiveData 方法很奇怪。

    所以它是在非 UI 线程上调用的。假设它读取的字节不是 -1。

    调用是必需的,所以它会回调自己。

    现在它读取一个字节并得到 -1(你说文件只有 1 位)。

    现在它永远在循环中旋转。

    此外,如果您在 UI 线程上调用该方法并且它读取一个字节,则它必须在输出之前读取 另一个 字节。

    如果您正在查看尚未关闭的网络流,这也可能在第二次调用 stream.ReadByte 时挂起。在流关闭之前,您的代码无法知道已经到达终点。这与文件不同。

    您还没有创建一种方法来逃避循环。此方法中没有任何内容将 listening 设置为 false。而且由于它在 UI 线程上旋转,因此您无法按下取消按钮或其他任何东西。

    我想你想做的是这样的:

    private void updateReceived(string s)
    {
        if (rtfReceiveWindow.InvokeRequired)
        {
            rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
        }
        rtfReceiveWindow.Text += s;
    }
    
    private void receiveData()
    {
        while (listening)
        {
            int recv = stream.ReadByte();
            if (recv != -1)
            {
                updateReceived(recv.ToString());
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      所以 Stream.ReadByte() 说:

      从流中读取一个字节并将流中的位置前移一个字节,如果在流的末尾则返回 -1。

      一旦网络流关闭,它就会保持这种状态。所以溪流说:我关门了。但是你的代码继续循环,得到-1,循环得到-1,循环。你需要做例如:

      void DataReader_Runner(object state)
      {
        Stream strm = (Stream)state;
        while (true) {
          int bi = strm.ReadByte(); // This blocks waiting for data...
          if (bi == -1)
            break;
          byte b = (byte)bi; // Now we know that it is not the special -1 int value
          ... use the new byte ...
        }
      }
      

      请注意,它修复了代码示例中的第二个问题...它执行 ReadByte 并将值丢弃,然后将 下一个字节发送到屏幕。

      上面的吉姆米歇尔已经说过了,但你似乎错过了他的答案。 :-)

      接受

      无论如何,有一个更早的问题......“流”被初始化为什么?假设您正在使用来自 32feet.NET 的 BluetoothListener(它使用相同的模式以及 FCL 的 TcpListener 和 IrDAListener),您需要接受一个新连接。你在某个地方这样做吗?我希望checkForConnection 这样做:

      while (!appQuitting) {
        // This blocks waiting for a incoming connection...
        var conn = listener.AcceptBluetoothClient();
        var strm = conn.GetStream();
        ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
      }
      

      【讨论】:

        【解决方案4】:

        表单可能没有正确创建,因为您的后台线程中的消息充斥着它,而后台线程总是在一个紧密的无限循环中执行。

        为什么不尝试使用“阻塞”流,以便它阻止线程执行,直到通过蓝牙接收到实际数据

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-06-07
          • 1970-01-01
          • 2018-10-16
          • 2011-04-12
          • 1970-01-01
          • 1970-01-01
          • 2021-11-17
          相关资源
          最近更新 更多