CancellationToken for the wrap?



  • Good day! I'm using a library for reading Modbus rtu. But I found that there was no waiting time and/or CancellationToken. What must be necessary in such long-term blocking tasks. ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints);

    Decided to slap and cancel the task after time.

     public async Task<ushort[]> ReadHoldingRegistersAsync(byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct)
        {
            return await await Task.Factory.StartNew(async () =>
            {
                Task<ushort[]> task = _master.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints);
    
            while (!task.IsCompleted)
            {
                ct.ThrowIfCancellationRequested();
            }
            return await task;
        }, ct);
    }
    

    Where I begin to create a hot task and then the task has not been completed by checking the state of the abrogation current.

    Calling code:

     using (var cts = new CancellationTokenSource(timeRespoune))        //время на ожидание ответа
    {
    try
    {
    byte[] sendBuffer = dataProvider.GetDataByte();
    if (sendBuffer == null || !sendBuffer.Any()) //READ
    {
    var takeBuff = await ReadHoldingRegistersAsync(slaveAddress, startAddress, (ushort)(dataProvider.CountGetDataByte / 2), cts.Token);

                } 
                else                                                                             
                _countTryingTakeData = 0;
    
            }
            catch (OperationCanceledException)
            {
    
                StatusString = string.Format("Время на ожидание ответа вышло");
    
                if (++_countTryingTakeData &gt; numberTryingTakeData)
                    Connect();
            }            
        }
    

    This is all in the interview cycle, i.e. waiting for N seconds if there's no response to OperationCanceledException, and we repeat it again.

    PROBLEMA:
    I'm looking at the dorm and the system with the thin abortion is working, but the port data are sent once. I mean, the board's status is over, but there's nothing in the port. The interruption of OperationCanceledException re-engineered a new disk (new id) entering the cancellation cycle, but there is no data at the port. Is that something I'm not doing or is that the library?



  • For starters, you're busy waiting: cycle

    while (!task.IsCompleted)
    {
        ct.ThrowIfCancellationRequested();
    }
    

    should consume a fairly large amount of resources, constantly requesting the status of the Task. It makes sense to rewrite this logic in a more friendly way:

    async Task WaitCancellation(CancellationToken ct)
    {
        var tcs = new TaskCompletionSource<int>();
        using (ct.Register(() => tcs.SetResult(0)))
            await tcs.Task;
    }
    

    public async Task<ushort[]> ReadHoldingRegistersAsync(
    byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct)
    {
    var mainTask =
    _master.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints);
    var cancellationWaitTask = WaitCancellation(ct);

    var firstFinishedTask = await Task.WhenAny(mainTask, cancellationWaitTask);
    
    if (firstFinishedTask == cancellationWaitTask)
        ct.ThrowIfCancellationRequested();
    
    return await mainTask;
    

    }

    Alone Task.Factory.StartNew I didn't need it.


    Now on the case. It's hard to cancel a run-off outside because it has to clean up internal data structures at the end. You're basically throwing a runaway disguise and then you start the next one. This may not be a well-founded idea, i.e. the parallel disk will probably use the same data structures, and two panels will interfere with each other. (Well, it's better to ask the library writers.)

    In your case, it appears you're using a library that writes at the port (serial?) so you can rustle the board, just close the port. Ooh. SerialPort I'm sorry. DisposeAnd the operation is inside. ReadHoldingRegistersAsync end of emergency with the exception, _master It's gonna be in a bad state, so you're gonna have to re-create. _master Again. It might not be such a bad decision. SerialPort)

    In this case, your external code is due upon arrival. OperationCanceledException (or whatever it takes) close the current _master and reconstruct it again. Or find a sucker. SerialPortclose it, catch an exception to his last operation, and finally close the current operation. _master and reconstruct it again.


    Of course, the clearest and most appropriate solution would be the availability of support CancellationToken Total ReadHoldingRegistersAsync♪ But it may not be possible, for example, if the target device fails after theconstruction of communication in the middle of the transmission of information to restore it without special teams.




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2