线程悬挂问题

时间:2017-07-03 11:11:24

标签: c# multithreading events

我正在研究C#如何处理线程和事件。为了做到这一点,我写了一个简单的程序,模拟温度计和三轴编码器(目前一切都只是随机生成的数据)。然后我写了一些事件:开始生成/读取编码器和温度计,如果温度超过阈值,在列表框中写入字符串,将温度数据记录在日志文件中,根据温度值使用不同的字符串。

为了做到这一点,我写了4个不同的类,它们是:

1st:Windows窗体类,Form1.cs

using System;
using System.Windows.Forms;
using Sensors;

namespace TestWindowsFormsApp
{
public partial class Form1 : Form
{

    private Termometer termometro;
    private AxisPosition assi;

    public Form1()
    {
        InitializeComponent();
        termometro = new Termometer();
        termometro.HighTemperatureReached += Termometro_HighTemperatureReached;
        new TemperatureLogger(termometro); 
        this.FormClosing += Form1_FormClosing; 
        assi = new AxisPosition();
        assi.PositionRead += Assi_PositionRead;
    }

    private void Assi_PositionRead(int x, int y, int z)
    {
        XValue.Invoke((MethodInvoker)delegate {
            XValue.Text = $"{x}";
            YValue.Text = $"{y}";
            ZValue.Text = $"{z}";
        });
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        termometro.HighTemperatureReached -= Termometro_HighTemperatureReached;
        assi.PositionRead -= Assi_PositionRead;
        termometro.StopReading();
        assi.StopReading();
    }

    private void Termometro_HighTemperatureReached(int value)
    {
        AlertsListBox.Invoke((MethodInvoker)delegate
        {
            AlertsListBox.Items.Add($"Temperatura alta, {value} °C");
        });
    }

    private void startButton_Click(object sender, EventArgs e)
    {
        try
        {
            termometro.StartReading();       
        }
        catch (InvalidOperationException exeption)
        {
            MessageBox.Show(exeption.Message);
        }
    }

    private void AxisResetButton_Click(object sender, EventArgs e)
    {
        //TODO: IMPLEMENT
    }

    private void AxisReadStart_Click(object sender, EventArgs e)
    {
        try
        {
            assi.StartReading();
        }
        catch (InvalidOperationException exeption)
        {
            MessageBox.Show(exeption.Message);
        }
    }
}
}

第二名:温度记录器类,TemperatureLogger.cs

using System;
using System.IO;
using Sensors;

namespace TestWindowsFormsApp
{
public class TemperatureLogger
{
    public TemperatureLogger(Termometer termometro)
    {
        termometro.TemperatureRead += Termometro_TemperatureRead;
        termometro.HighTemperatureReached += Termometro_HighTemperatureReached;
    }

    private void Termometro_HighTemperatureReached(int value)
    {

        File.AppendAllText("temperature.log", $"{DateTime.Now} - !!!WARNING!!! Temperature read: {value} °C\n");
    }

    private void Termometro_TemperatureRead(int value)
    {
        File.AppendAllText("temperature.log", $"{DateTime.Now} - Temperature read: {value} °C\n");
    }
}
}

3rd:Axes位置类,AxisPosition.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Sensors
{
    public class AxisPosition
    {
        private Thread readingThread;
        private bool isReading = false;
        public delegate void AxisNotification(int x, int y, int z);
        public event AxisNotification PositionRead;
        public event AxisNotification PositionSet;
        private int x_ref = 0;
        private int y_ref = 0;
        private int z_ref = 0;

        public void StartReading()
        {
            if (readingThread != null)
                throw new InvalidOperationException("Positioner is already reading!");

            readingThread = new Thread(() =>
            {
                while (isReading)
                {
                    var x = new Random().Next(1000) - x_ref;
                    var y = new Random().Next(300) - y_ref;
                    var z = new Random().Next(600) - z_ref;

                    if (PositionRead != null)
                        PositionRead(x, y, z);

                    if (PositionSet != null)
                        PositionSet(x, y, z);

                    Thread.Sleep(200);
                }
                Console.WriteLine("Exit from axes Thread.");
            });

            isReading = true;
            readingThread.Priority = ThreadPriority.Lowest;
            readingThread.Start();

        }


        public void StopReading()
        {

            isReading = false;
            if (readingThread != null)
            {
                int watchdog = 0;
                while (readingThread.IsAlive && watchdog <= 50)
                {
                    watchdog++;
                    Thread.Sleep(100);
                }
                readingThread = null;
            }
        }    
    }
}

最后,第4课,一读温度,Termometer.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Sensors
{
    public class Termometer
    {

        private Thread readingThread;
        public void StartReading()
        {

            if (readingThread != null)
                throw new InvalidOperationException("Termometer is already reading!");

            readingThread = new Thread(() =>
                        {
                            try
                            {
                                while (true)
                                {
                                    var read = new Random().Next(100);

                                    if (read > 50 && HighTemperatureReached != null)
                                        HighTemperatureReached(read);

                                    if (TemperatureRead != null)
                                        TemperatureRead(read);

                                    Thread.Sleep(200);
                                }
                            }
                            catch (ThreadAbortException) {
                                // Clean up
                            }

                            Console.WriteLine("Esco dal Thread di lettura temperature.");
                        }
                       );

            readingThread.Priority = ThreadPriority.Lowest;
            readingThread.Start();

        }
        public event TemperatureNotificationDelegate HighTemperatureReached;
        public event TemperatureNotificationDelegate TemperatureRead;    

        public void StopReading()
        {
            if (readingThread != null)
            {
                readingThread.Abort();
                readingThread = null;
            }
        }    
    }
}

一切正常,但我关闭窗体窗口时遇到问题:有时(似乎是随机的)某些线程仍然挂起,我必须手动关闭(因此使用Abort()方法)。这是一个强力解决方法,但我更喜欢让线程优雅地退出,就像我在轴1中所做的那样。 我的问题是:为什么有时线程不会退出,但仍然挂起?

似乎通过doind一些调试条件isreagind == false没有得到正确的阐述,但我无法理解为什么。

感谢您的协助。

0 个答案:

没有答案
相关问题