I get the data from the TCP server, if the request lasts more than 1 second, then we finish the Task while waiting for the response and throw out a TimeoutException("....") . Also, if CancellationToken arrives, then immediately disable everything and throw away OperationCanceledException("....") .
In different projects I noticed different implementations of such functionality, but they are all muddy, help me figure it out.
1. The most frequent option
public static T WithTimeout<T>(this Task<T> task, int time, CancellationToken ct) { var isCompletedSuccessfully = task.Wait(time, ct); if (isCompletedSuccessfully) { return task.Result; } throw new TimeoutException("The function has taken longer than the maximum time allowed."); } //Но тут task мы не отключаем, тоесть будем плодить висячие таски. //task.Wait() синхронное ожидание заврешения, что тоже неверно. 2. Also used in a couple of projects.
public static async Task<T> WithTimeout<T>(Task<T> task, int time, CancellationToken ct) { Task delayTask = Task.Delay(time, ct); Task firstToFinish = await Task.WhenAny(task, delayTask); if (firstToFinish == delayTask) { task.ContinueWith(HandleException, ct); //к основной задаче прикрепили обработку иключений throw new TimeoutException(); } return await task; } private static void HandleException<T>(Task<T> task) { if (task.Exception != null) { ; //чтото делаем с исключеним возникшим в основной задаче. } } //task также не отключаем а подписываемся на резульат выполнения и все таки ЖДЕМ. And if you just use CancelAfter? Well, yes of the minuses constantly need to create a CancellationTokenSource before calling the method and associate task with it. But he seems to be working properly?
public static async Task<T> WithTimeout<T>(this Task<T> task, int time, CancellationTokenSource ctsTask) { ctsTask.CancelAfter(time); try { return await task; } catch (OperationCanceledException ex) { throw new TimeoutException("The function has taken longer than the maximum time allowed."); } } **ИСПОЛЬЗОВАНИЕ:** public async Task<byte[]> TakeDataAsync(int nbytes, int timeOut, CancellationToken ct) { byte[] bDataTemp = new byte[256]; var ctsTimeout = new CancellationTokenSource();//токен сработает по таймауту в функции WithTimeout var cts = CancellationTokenSource.CreateLinkedTokenSource(ctsTimeout.Token, ct); // Объединенный токен, сработает от выставленного ctsTimeout.Token или от ct int nByteTake = await _terminalNetStream.ReadAsync(bDataTemp, 0, nbytes, cts.Token).WithTimeout(timeOut, ctsTimeout); if (nByteTake == nbytes) { var bData = new byte[nByteTake]; Array.Copy(bDataTemp, bData, nByteTake); return bData; } return null; } Those. We connect tasks through CancellationTokenSource. And just cancel the task on time. To cancel a task for any of the tokens using CancellationTokenSource.CreateLinkedTokenSource ()
it is still not clear how to distinguish the completed task by time or by CANCEL, since cts is common. And you also need the fastest version of performance, because client is used on RasberiPi under AspNetCore.
Do I need to kill the CancellationTokenSource through Dispose after working out the function?