Tasks, main task, sub task
Hello,
How are they handled and terminated correctly. Sample examples would be good. I trigger a Cancel and all tasks should exit cleanly. How do I achieve this? The problem is, there are so many options, but few good ones. You have to know them. I want to do it right. It only works if I know the possibilities.
Picture:
Picture States
Process -> Task/Thread
ServerData -> Task/Thread
Print -> Task/Thread
I am a bit in the dark, could someone let me know how I would need to create the architecture correctly. With sample code.
Can I give a TaskName, like Process ServerData Print If I press CANCEL, then check the Thread, task name.
I have states, IN; START; OUT These are activated and set externally. Depending on the state, it may be that tasks have not yet been processed, although the next state is already set.
Background, a part is moved mechanically and set the event. I simulate it with bottons. Something is wrong, what, I don't know. Can you give me tips please?
Code:
private void btnIN_Click(object sender, EventArgs e)
{
MyServiceObject.CurrentState = STATE.In;
}
private void btnSTART_Click(object sender, EventArgs e)
{
MyServiceObject.CurrentState = STATE.START;
}
private void btnOUT_Click(object sender, EventArgs e)
{
MyServiceObject.CurrentState = STATE.OUT;
}
private void Form1_Load(object sender, EventArgs e)
{
}
// ************************************************
public enum STATE
{
NotDefine = -1,
In = 0,
START = 1,
OUT = 2,
CANCEL = 3
}
public class ServerData
{
public int Index { set; get; }
public string Code { set; get; }
public string BestBefore { set; get; }
}
public class ServerDataList : List<ServerData>
{
public bool DataReady { set; get; }
public Task GetServerDataVariant2(CancellationToken ct, ConcurrentBag<Task> cb)
{
Task t;
t = Task.Run(() =>
{
//cb.Add(t);
if (ct.IsCancellationRequested)
{
Trace.WriteLine($"GetServerDataAsync Task id= '{Thread.CurrentThread.ManagedThreadId}' was cancelled before it got started.");
ct.ThrowIfCancellationRequested();
}
var list = new List<ServerData>();
//for (int i = 0; i < 300000; i++)
for (int i = 0; i < 200; i++)
{
Add(new ServerData()
{
BestBefore = "12/2023",
Code = $"{i,22:D22}",
Index = i
});
Trace.WriteLine($"Code= '{this[Count - 1].Code}', ThreadID= '{Thread.CurrentThread.ManagedThreadId}'");
Thread.Sleep(2);
if (ct.IsCancellationRequested)
{
Trace.WriteLine($"GetServerDataVariant2 Task '{Thread.CurrentThread.ManagedThreadId}' cancelled");
// Trace.WriteLine($"GetServerDataVariant2 Task '{t.Id}' cancelled");
//ct.ThrowIfCancellationRequested();
break;
}
}
// return t; // list;
});
cb.Add(t);
return t;
}
public Task<List<ServerData>> GetServerDataAsync(CancellationToken ct, ConcurrentBag<Task> cb)
{
// var serverData = await GetServerDataAsync();
// I can't wait, because the product is moving meanwhile the request of the server data.
// Was cancellation already requested?
return Task.Run(() =>
{
if (ct.IsCancellationRequested)
{
Trace.WriteLine($"GetServerDataAsync Task id= '{Thread.CurrentThread.ManagedThreadId}' was cancelled before it got started.");
ct.ThrowIfCancellationRequested();
}
var list = new List<ServerData>();
//for (int i = 0; i < 300000; i++)
for (int i = 0; i < 200; i++)
{
Add(new ServerData()
{
BestBefore = "12/2023",
Code = $"{i,22:D22}",
Index = i
});
Trace.WriteLine($"Code= '{this[Count - 1].Code}', ThreadID= '{Thread.CurrentThread.ManagedThreadId}'");
Thread.Sleep(2);
if (ct.IsCancellationRequested)
{
Trace.WriteLine($"GetServerDataAsync Task '{Thread.CurrentThread.ManagedThreadId}' cancelled");
ct.ThrowIfCancellationRequested();
}
}
return list;
});
}
public void GetServerData(CancellationToken ct)
{
//https://learn.microsoft.com/de-de/dotnet/standard/parallel-programming/how-to-cancel-a-task-and-its-children
// Was cancellation already requested?
if (ct.IsCancellationRequested)
{
Trace.WriteLine($"Task id= '{Thread.CurrentThread.ManagedThreadId}' was cancelled before it got started.");
ct.ThrowIfCancellationRequested();
}
DataReady = false;
//for (int i = 0; i < 300000; i++)
for (int i = 0; i < 200; i++)
{
Add(new ServerData()
{
BestBefore = "12/2023",
Code = $"{i,22:D22}",
Index = i
});
Trace.WriteLine($"Code= '{this[Count - 1].Code}', ThreadID= '{Thread.CurrentThread.ManagedThreadId}'");
Thread.Sleep(2);
if (ct.IsCancellationRequested)
{
Trace.WriteLine($"Task '{Thread.CurrentThread.ManagedThreadId}' cancelled");
ct.ThrowIfCancellationRequested();
}
}
DataReady = true;
}
public bool IsDataFromServerReady(CancellationToken ct)
{
while (!DataReady)
{
Thread.Sleep(50);
}
return DataReady;
}
public bool IsProductResult(int amount)
{
if (amount > 30)
return true;
return false;
}
}
public class MyService
{
ServerDataList MyServerData = new ServerDataList();
ConcurrentBag<Task> CB;
public CancellationTokenSource TokenSource = new CancellationTokenSource();
public CancellationToken Ct;
private ManualResetEvent ManualResetEvent = new ManualResetEvent(false);
private Stopwatch SW = new Stopwatch();
public STATE CurrentState = STATE.NotDefine;
public int EventNo { set; get; } = 0;
public MyService()
{
Ct = TokenSource.Token;
CB = new ConcurrentBag<Task>();
}
public async Task<int> Process()
{
try
{
while (true)
{
switch (CurrentState)
{
default:
break;
case STATE.In:
CurrentState = STATE.NotDefine;
ManualResetEvent.Reset();
Trace.WriteLine($"Work {CurrentState}, ThreadID= '{Thread.CurrentThread.ManagedThreadId}' seconds= '{SW.Elapsed.Seconds}'");
EventIn();
break;
case STATE.START:
CurrentState = STATE.NotDefine;
EventStart();
break;
case STATE.OUT:
CurrentState = STATE.NotDefine;
break;
case STATE.CANCEL:
TokenSource.Cancel();
ManualResetEvent.Set();
Trace.WriteLine($"Work {CurrentState}, ThreadID= '{Thread.CurrentThread.ManagedThreadId}'");
break;
}
if (CurrentState == STATE.CANCEL)
break;
await Task.Delay(10);
}
}
catch (OperationCanceledException ex)
{
Trace.WriteLine($"\n{nameof(OperationCanceledException)} thrown\n{ex.Message}\n{ex.StackTrace}");
}
finally
{
// if (ManualResetEvent.WaitOne(2000))
// TokenSource.Dispose();
await Task.WhenAll(CB.ToArray());
}
return 0;
}
public async void EventIn()
{
//try
//{
ManualResetEvent.Reset();
//Task.Run(() => MyServerData.GetServerData(Ct));
//Task<List<ServerData>> serverData = await MyServerData.GetServerDataAsync();
//var serverData = await MyServerData.GetServerDataAsync(Ct, CB);
await MyServerData.GetServerDataVariant2(Ct, CB);
ManualResetEvent.Set();
//}
//catch (OperationCanceledException)
//{
// Console.WriteLine($"\n{nameof(OperationCanceledException)} thrown\n");
//}
//finally
//{
// //TokenSource.Dispose();
//}
//MessageBox.Show("EventIn");
}
public void EventStart()
{
//ServerDataList MyServerDataSub = new ServerDataList();
//await Task.Run(() => MyServerData.IsDataFromServerReady(Ct));
//MessageBox.Show("EventStart");
if (!ManualResetEvent.WaitOne(5000))
{
TokenSource.Cancel();
//MessageBox.Show("TimeOut EventStart", "Info....", MessageBoxButtons.OK, MessageBoxIcon.Error);
Trace.WriteLine($"EventStart TokenSource.Cancel() Timeout #### ");
}
else
{
Trace.WriteLine($"EventStart All fine, product can be produced #### ");
foreach (var item in MyServerData)
{
Trace.WriteLine($"Produce Index= '{item.Index}', Code= '{item.Code}', BestBefore= '{item.BestBefore}' ThreadID= '{Thread.CurrentThread.ManagedThreadId}'");
//await Task.Delay(1000);
Thread.Sleep(1000);
}
}
}
public async Task<bool> EventOut()
{
var result = await Task.Run(() => MyServerData.IsProductResult(77));
return result;
// return await Task.Run(() => MyServerData.IsProductResult(45)).Result;
}
}
MyService MyServiceObject = new MyService();
private async void btnTASK_Click(object sender, EventArgs e)
{
MyServiceObject = new MyService();
await Task.Run(() => MyServiceObject.Process());
// MessageBox.Show("TEST Mandelbrot Ready");
}
private void btnCancel_Click(object sender, EventArgs e)
{
MyServiceObject.CurrentState = STATE.CANCEL;
}