在运行3个进程/线程故障时陷入winform

时间:2018-04-30 10:36:25

标签: c# multithreading winforms

我是Windows窗体中的新手。我正在开发一个单一的表单应用程序,它在Web浏览器中显示消息发送选项以及实时视频流,并使用图表显示实时脉冲图。我可以以其他形式单独成功运行这些进程,但现在我想将所有进程嵌入到一个表单中,但是只要应用程序运行,它就会挂起,只显示视频输入和光标无法移动。我需要一个人来引导我进行线程化。三江源

这是我想要的表格和代码。请帮忙。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Diagnostics;

namespace ClientApp
{
    public partial class Form1 : Form
    {
        private string myMessage = "";
        private TcpClient client = new TcpClient();
        private IPEndPoint serverEndPoint = new 
                                            IPEndPoint(IPAddress.Parse("server 
                                            ip"), port1);
        Socket socket = new Socket(AddressFamily.InterNetwork, 
                        SocketType.Stream, ProtocolType.Tcp);


        public Form1()
        {
            InitializeComponent();
            client.Connect(serverEndPoint);
            socket.Connect("server ip", port2);


            //thread for running video stream
            Thread t1 = new Thread(threadURL);
            t1.Start();

        }

        void threadURL()
        {
            string URL = "server ip";
            webBrowser2.Navigate(URL);
        }


        // now the chat part(send message to Rpi)

        private void RtbClientKeyDown(object sender, KeyEventArgs e)
        {

            if (e.KeyData != Keys.Enter || e.KeyData != Keys.Return)
            {
                myMessage += (char)e.KeyValue;
            }
            else
            {

                SendMessage(myMessage);
                myMessage = "";

            }

        }

        private void SendMessage(string msg)
        {
            NetworkStream clientStream = client.GetStream();

            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes(msg);

            clientStream.Write(buffer, 0, buffer.Length);
            clientStream.Flush();


        }

        //realtime pulse plot part received from socket
        System.Windows.Forms.Timer chartTimer = new 
        System.Windows.Forms.Timer();

        private void InitChart()
        {
            DateTime time = DateTime.Now;
            chartTimer.Interval = 1000;
            chartTimer.Tick += chartTimer_Tick;
            chart1.DoubleClick += chartDemo_DoubleClick;

            Series series = chart1.Series[0];


            chartTimer.Start();

        }

        //socket receiving pulse values from Rpi
        int ReceiveText()
        {

            byte[] buffer = new byte[1024];
            int iRx = socket.Receive(buffer);
            char[] chars = new char[iRx];

            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(buffer, 0, iRx, chars, 0);
            string recv = new string(chars);
            int final = Convert.ToInt16(recv);

            return final;

        }


        void chartDemo_DoubleClick(object sender, EventArgs e)
        {
            chart1.ChartAreas[0].AxisX.ScaleView.Size = 5;
            chart1.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = true;
            chart1.ChartAreas[0].AxisX.ScrollBar.Enabled = true;
        }


        private void LivePulseplot()
        {

            Series series = chart1.Series[0];
            chartTimer.Start();

            series.Points.AddXY(DateTime.Now.ToString("hh:mm:ss"), 
                                                      ReceiveText());
            chart1.ChartAreas[0].AxisX.ScaleView.Position = series.Points.Count - 5;

        }


        void chartTimer_Tick(object sender, EventArgs e)
        {

            Thread tP = new Thread(LivePulseplot);
            tP.Start();

        }
    }
}

1 个答案:

答案 0 :(得分:0)

表单挂起的原因是主线程(创建并呈现UI的主线程)始终在工作。

您有几种可能性可以防止这种情况发生。 一种是启动在后台执行操作的线程(尽管这可能很棘手,因为您需要确保更新UI的任何内容都将该责任委托给UI线程,因为其他线程不允许更改在主线程上创建的内容),就像在代码中一样,其他人正在使用async / await模式或者例如BackgroundWorkers。

您的实施中存在一些问题。 在chartTimer_Tick中,您将开始一个新线程。每次计时器滴答时(每1000毫秒)都会发生这种情况。您不应该在LivePulsePlot中调用chartTimer.Start(),因为计时器已在运行(或者您不会点击该功能)。一旦你在计时器上调用了Start(),它就会每1000毫秒继续执行'Tick'功能,直到你调用Stop()。

此外,System.Windows.Forms.Timer在UI线程上执行其方法,这将导致UI在函数运行时冻结。您可以使用其他计时器,例如System.Timers.Timer如果你想在后台运行一些东西。

在后台线程中执行此操作时需要考虑的一件事是,无论何时想要更新某个screen-element,都必须要求UI线程为您执行此操作(而不是后台线程) 。 在这里阅读更多相关信息: https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls

更好的方法(虽然你现在需要投入更多的时间)是使用async / await或BackgroundWorkers,但是你开始实现它的方式也可以工作,有点努力。

希望这有帮助。