我使用NModbus4通过ModbusRTU(RS485)进行通信。我的程序需要不断从设备获取数据,该设备经常断开连接。当设备断开连接时,我发现超时异常(可以理解),因为程序是滞后的(通过表单,按下按钮等),因为它等待设备响应一段时间。
是否可以将Modbus连接移动到单独的线程以与用户界面并行处理(或者有更好的选择)?
如果是这样,请帮我一个简单的例子,说明如何结合事件(我通过事件传递设备数据和信息来显示数据)。
示例代码:
public MainGui()
{
InitializeComponent();
DataTransport DataManagment = new DataTransport(); //DataTransport is a class that handles communication and publishes event 'DataSent'
DataManagment.DataSent += new EventHandler<DataSentArgs>(UnpackData);
}
private void slaveDataReqTimer_Tick(object sender, EventArgs e)
{
//Timer that is responsible for fetching data
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
DataManagment.RequestData();
}).Start();
}
public void UnpackData(object sender, DataSentArgs e)
{
//Doing some stuff when data arrives
}
此代码的问题在于我无法将事件从新线程传递到当前线程(另外我不知道线程的方法是否正确)。
我刚开始使用C#和.NET,因此示例代码可能不符合标准惯例 - 对不起。
答案 0 :(得分:0)
线程是一个太低级的原语 - 我建议调查任务并尽可能避免使用线程。
这是代码在您的情况下的样子。 DataManagement.RequestData调用发生在从线程池中获取的另一个线程上,但在此之后,您再次进入主线程的上下文,因此您不必执行任何同步/编组/等。 如果ProcessData方法也很慢,那么您可以像使用DataManagement.RequestData一样 - 在任务上执行它。同样,不需要同步。
public MainWindow()
{
InitializeComponent();
var cts = new CancellationTokenSource();
Unloaded += delegate { cts.Cancel(); };
ProcessData(cts.Token);
}
async void ProcessData(CancellationToken ct)
{
try
{
while (true)
{
ct.ThrowIfCancellationRequested();
try
{
var dataItem = await Task.Run(() => DataManagement.RequestData());
ProcessData(dataItem);
}
catch(Exception_Thrown_By_RequestData e)
{
// decide what do - either break the loop or continue if
// this is not a heavy faiulre
}
await Task.Delay(DelayTime, ct);
}
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
}