使用线程进行外部通信(PC - > RS485设备)

时间:2018-05-01 08:40:42

标签: c# .net

我使用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,因此示例代码可能不符合标准惯例 - 对不起。

1 个答案:

答案 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) { }
}