C# 挂线问题
我正在研究C#如何处理线程和事件。为了做到这一点,我编写了一个简单的程序来模拟温度计和三轴编码器(目前一切都是随机生成的数据)。然后我写了一些事件:开始生成/读取编码器和温度计,在列表框中写入一个字符串(如果温度超过阈值),在日志文件中记录温度数据,根据温度值使用不同的字符串 为此,我编写了4个不同的类,如下所示: 第一:windows窗体类Form1.csC# 挂线问题,c#,multithreading,events,C#,Multithreading,Events,我正在研究C#如何处理线程和事件。为了做到这一点,我编写了一个简单的程序来模拟温度计和三轴编码器(目前一切都是随机生成的数据)。然后我写了一些事件:开始生成/读取编码器和温度计,在列表框中写入一个字符串(如果温度超过阈值),在日志文件中记录温度数据,根据温度值使用不同的字符串 为此,我编写了4个不同的类,如下所示: 第一:windows窗体类Form1.cs using System; using System.Windows.Forms; using Sensors; namespace T
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");
}
}
}
第三:AxisPosition类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;
}
}
}
}
一切正常,但我在关闭窗体窗口时遇到了一个问题:有时(似乎是随机的)某些线程仍然挂起,我必须手动关闭(因此使用Abort()方法)。这是一个强力的解决方法,但我更愿意让线程优雅地退出,就像我在axes one中所做的那样。
我的问题是:为什么有时线程没有退出,但仍然挂起
通过一些调试,似乎没有正确地解释条件isreagind==false,但我不理解为什么
谢谢您的帮助。当您关闭表单窗口时,它卡在哪里了。基本上,调用事件isclose,线程运行条件设置为false,它应该正常关闭。这种情况有时不会发生。而应用程序则一直处于停滞状态。我通过使用Thread.Abort()方法找到了一个转机,但我想知道发生了什么,以防止在生产阶段出现这种行为。XValue.Invoke()是一个等待发生的死锁。如果它发生在UI线程调用StopReading()时,那么您将遇到问题。总是喜欢BeginInvoke()。这不是唯一的问题,类似bool的isReading不是同步对象,工作线程可能永远不会看到它变为false。这里没有明显的理由说明线程为什么有用,它们所做的只是睡眠。换个简单的计时器,在工具箱里找到一个。谢谢你的回答!然而,我有几个问题:为什么会出现僵局?如果我理解事情是如何工作的,那么这些方法只是调用表单GUI的更新,所以即使表单不再存在,它们也应该异常关闭,而不是挂起。。。我说得对吗?此外,bool值怎么会失败?只要gui存在,它就会工作。。。你能解释一下吗?我知道在这里使用线程是。。不是最优的,但这是一个针对事件和线程的实践应用程序。
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;
}
}
}
}