how to run a timer in a finite loop in C# - c#

I have a task where I have to record a video in multiple segments. Let's take the scenario in this way, the user has started recording a video through a webcam and after 5 seconds it has stopped the recording, now we have the value of 5 seconds and our system will start recording the video again for the next 5 seconds and save it in a file. This process will run for multiple times(the value is already set by the user, let's say 3 times).
This is what I want to do in real.
And the Block of code that I shared is an illustration of the real task where code will run a task wait for some time, and repeat the process till it meets a condition which in our case is 3.
This piece of code is working fine but sometimes it skips the counting of seconds. By skipping I mean it will show 1 then lag for 2 seconds then will show 2 and 3 and so on.
I am afraid if I use this technique it might give me the wrong output and I need to be very precise with the recording time.
Is there any way to improve this piece of code?
Stopwatch sw;
private void btnStart_Click(object sender, EventArgs e)
{
sw = new Stopwatch();
timer1.Enabled = true;
sw.Start();
}
int counter = 1;
private void timer1_Tick(object sender, EventArgs e)
{
if (sw.Elapsed > TimeSpan.FromSeconds(4))
{
sw.Reset();
if (counter < 3)
{
sw.Start();
counter++;
}
else
{
sw.Reset();
timer1.Stop();
counter = 0;
MessageBox.Show("Counter has finished +"counter.ToString());
}
}
lblTime.Text = string.Format("{0:hh\\:mm\\:ss}", sw.Elapsed);
}

The question is a bit unclear and doesn't explain what needs to run. That matters.
One way to repeat a 5-second task 3 times would be to use a CancellationTokenSource that triggers after 5 seconds inside a loop. The worker code would have to check a CancellationToken to see when it needs to terminate :
async Task DoWorkAsync(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
// The Block
}
}
async void btnStart_Clicked(object sender,EventArgs args)
{
var count=3;
var sw = new Stopwatch();
for (int i=0;i<count;i++)
{
sw.Restart();
using var cts=new CancellationTokenSource(TimeSpan.FromSeconds(5));
await DoWorkAsync(cts.Token);
lblTime.Text = $("{sw.Elapsed:hh\\:mm\\:ss}");
}
MessageBox.Show($"Counter has finished + {count}");
}
The UI can be updated after each await call, or through a Progress class. If the code block runs for a long time it can be made to run in the background with Task.Run that can be cancelled using the same token. If the block executes asynchronous operations, they could be cancelled as well :
async Task DoWorkAsync(CancellationToken token,IProgress<string> pg)
{
try
{
while(!token.IsCancellationRequested)
{
await Task.Run(()=>{
//Do Work 1
pg.Report("Done 1");
//Do Work 2
pg.Report("Done 2");
},token);
}
}
catch(OperationCanceledException)
{
pg.Report("Time's up!");
}
}
async void btnStart_Clicked(object sender,EventArgs args)
{
var pg=new Progress(DisplayProgress);
var count=3;
var sw = new Stopwatch();
for (int i=0;i<count;i++)
{
sw.Restart();
using var cts=new CancellationTokenSource(TimeSpan.FromSeconds(5));
await DoWorkAsync(cts.Token,pg);
lblTime.Text = $("{sw.Elapsed:hh\\:mm\\:ss}");
}
MessageBox.Show($"Counter has finished + {count}");
}
void DisplayProgress(string msg)
{
lblMessage.Text=msg;
}

Related

Deadlock using async Task and SemaphoreSlim

we are running an ASP.NET 6 webapplication and are having strange issues with deadlocks.
The app suddenly freezes after some weeks of operations and it seems that it might be caused by our locking mechanism with the SemaphoreSlim class.
I tried to reproduce the issue with a simple test-project and found something strange.
The following code is simply starting 1000 tasks where each is doing some work (requesting semaphore-handle, waiting for 10 ms and releasing the semaphore).
I expected this code to simply execute one task after another. But it freezes because of a deadlock in the first call of the DoWork method (at await Task.Delay(10)).
Does anyone know why this causes a deadlock? I tried exactly the same code with ThreadPool.QueueUserWorkItem instead of Task.Run and Thread.Sleep instead of Task.Delay and this worked as expected. But as soon as I use the tasks it stops working.
Here is the complete code-snippet:
internal class Program
{
static int timeoutSec = 60;
static SemaphoreSlim semaphore = new SemaphoreSlim(1);
static int numPerIteration = 1000;
static int iteration = 0;
static int doneCounter = numPerIteration;
static int successCount = 0;
static int failedCount = 0;
static Stopwatch sw = new Stopwatch();
static Random rnd = new Random();
static void Main(string[] args)
{
Task.WaitAll(TestUsingTasks());
}
static async Task TestUsingTasks()
{
while (true)
{
var tasks = new List<Task>();
if (doneCounter >= numPerIteration)
{
doneCounter = 0;
if (iteration >= 1)
{
Log($"+++++ FINISHED TASK ITERATION {iteration} - SUCCESS: {successCount} - FAILURES: {failedCount} - Seconds: {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Magenta);
}
iteration++;
sw.Restart();
for (int i = 0; i < numPerIteration; i++)
{
// Start indepdent tasks to do some work
Task.Run(async () =>
{
if (await DoWork())
{
successCount++;
}
else
{
failedCount++;
}
doneCounter++;
});
}
}
await Task.Delay(10);
}
}
static async Task<bool> DoWork()
{
if (semaphore.Wait(timeoutSec * 1000)) // Request the semaphore to ensure that one 1 task at a time can enter
{
Log($"Got handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Green);
var totalSec = sw.Elapsed.TotalSeconds;
await Task.Delay(10); // Wait for 10ms to simulate some work => Deadlock seems to happen here
Log($"RELEASING LOCK handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}. WAIT took " + (sw.Elapsed.TotalSeconds - totalSec) + " seconds", ConsoleColor.Gray);
semaphore.Release();
return true;
}
else
{
Log($"ERROR: TASK handle failed for {iteration} within {sw.Elapsed.TotalSeconds:F1} sec", ConsoleColor.Red);
return false;
}
}
static void Log(string message, ConsoleColor color)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.White;
}
}
Thanks in advance!
But it freezes because of a deadlock in the first call of the DoWork method (at await Task.Delay(10)).
I would argue that it is not deadlock but a thread starvation issue. If you wait long enough you will see that threads will be able to finish the simulation wait from time to time.
The quick fix here is using non-blocking WaitAsync call with await:
static async Task<bool> DoWork()
{
if (await semaphore.WaitAsync(timeoutSec * 1000))
{
...
}
}
Also note:
It is recommended to wrap the code after Wait.. into try-finally block and release the semaphore in the finally.
Incrementing counters in parallel environments better should be done in atomic fashion, for example with Interlocked.Increment.

Await Task.Delay() spend too much time

In C# I have an example:
public async static Task TaskTest(int i)
{
await Task.Delay(1);
Console.WriteLine($"{i}. {DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadId:{Thread.CurrentThread.ManagedThreadId} Start");
int count = 1;
while (true)
{
DoSomeThing(count);
var stopWatch = new Stopwatch();
stopWatch.Start();
await Task.Delay(100);
stopWatch.Stop();
if (stopWatch.Elapsed.TotalMilliseconds > 200)
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Id:{count} Time:{DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadID:{Thread.CurrentThread.ManagedThreadId} Time Delay:{stopWatch.Elapsed.TotalMilliseconds }");
Console.ForegroundColor = ConsoleColor.White;
count++;
}
}
public async static Task DoSomeThing(int index)
{
await Task.Delay(1);
Task.Delay(1000).Wait();
}
private static void Main(string[] args)
{
int i = 1;
while (i < 2)
{
TaskTest(i);
Task.Delay(1).Wait();
i++;
}
Console.ReadKey();
}
Here is my result
Result
Id:8 Time:23:03:59 972 ThreadID:12 Time Delay:582.6348
Id:22 Time:23:04:01 974 ThreadID:14 Time Delay:552.7234000000001
Id:42 Time:23:04:04 967 ThreadID:8 Time Delay:907.3214
I don't know why Task sometimes delay more than 200 milliseconds.
Update:
Thank for all answer.
I update my code to use Thread and Thread.Sleep() and Task.Run(). I increase number of Threads run forever to 500. I tested in 30 minutes and 500 threads never sleep more than 200ms.
Do you think that is bad code?
Please leave a comment!
Thank you so much!
public static void TaskTest(object i)
{
Console.WriteLine($"{i} Start");
int count = 1;
while (true)
{
// Open Task to do work
Task.Run(() => { DoSomeThing(count); });
var stopWatch = new Stopwatch();
stopWatch.Start();
Thread.Sleep(100);
stopWatch.Stop();
if (stopWatch.Elapsed.TotalMilliseconds > 200)
{
Console.WriteLine($"Id:{count} Time:{DateTime.Now.ToString("HH:mm:ss fff")} " +
$"ThreadID:{Thread.CurrentThread.ManagedThreadId} Time Delay:{stopWatch.Elapsed.TotalMilliseconds }");
}
count++;
}
}
public static void DoSomeThing(int index)
{
Thread.Sleep(1000); // Time spent complete work
}
private static void Main(string[] args)
{
int i = 0;
while (i < 500)
{
// Open Thread for TaskTest
Thread tesThread = new Thread(TaskTest);
tesThread.IsBackground = true;
tesThread.Start(i);
i++;
}
Console.WriteLine("Finish init");
Console.ReadKey();
}
Task.Delay, like any other multi-threaded sleep function, yields the thread it's running on back to the system (or in the case of the thread pool, back to the thread pool scheduler), asking to be re-scheduled some time after the amount of time specified.
That is the only guarantee you have, that it will wait at least the amount specified. How long it will actually wait heavily depends on your thread pool load (you're delaying an awful lot of tasks there), general system load (there's thousands of threads at any given point in time to be scheduled on an average computer OS) and on your CPU&OS's capability to schedule threads quickly (in Windows, look at timeBeginPeriod).
Long story short, if precise timing matters to you, don't relinquish your thread.

Tasks are starting sequencial instead of parallel

I need to start tasks in parallel, but I choose to use Task.Run instead of Parallel.Foreach, so I can get some feedback when all tasks finished and enable UI controls.
private async void buttonStart_Click(object sender, EventArgs e)
{
var cells = objectListView.CheckedObjects;
if(cells != null)
{
List<Task> tasks = new List<Task>();
foreach (Cell c in cells)
{
Cell cell = c;
var progressHandler = new Progress<string>(value =>
{
cell.Status = value;
});
var progress = progressHandler as IProgress<string>;
Task t = Task.Run(() =>
{
progress.Report("Starting...");
int a = 123;
for (int i = 0; i < 200000; i++)
{
a = a + i;
Task.Delay(500).Wait();
}
progress.Report("Done");
});
tasks.Add(t);
}
await Task.WhenAll(tasks);
Console.WriteLine("Done, enabld UI controls");
}
}
So what I expect is that I see in UI "Starting..." almost instantly for all items. What I actually see is first 4 items are "Starting..." (I guess because all 4 CPU cores are used per thread), then each second or less new item is "Starting". I have total 37 items and it takes around 30 seconds for all items to start all tasks.
How can I make it as parallel as possible?
How can I make it as parallel as possible?
The part of inner for loop is simulating long running CPU-bound job, which I would like to start at the same time as much as possible.
It's already as parallel as possible. Starting 37 threads that all have CPU-bound work to do will not make it go any faster, since you're apparently running it on a 4-core machine. There are 4 cores, so only 4 threads can actually run at a time. The other 33 threads are going to be waiting while 4 are running. They would only appear to run simultaneously.
That said, if you really want to start up all those thread pool threads, you can do this by calling ThreadPool.SetMinThreads.
I need to start tasks in parallel, but I choose to use Task.Run instead of Parallel.Foreach, so I can get some feedback when all tasks finished and enable UI controls.
Since you have parallel work to do, you should use Parallel. If you want the nice resume-on-the-UI-thread behavior of await, then you can use a single await Task.Run, something like this:
private async void buttonStart_Click(object sender, EventArgs e)
{
var cells = objectListView.CheckedObjects;
if (cells == null)
return;
var workItems = cells.Select(c => new
{
Cell = c,
Progress = new Progress<string>(value => { c.Status = value; }),
}).ToList();
await Task.Run(() => Parallel.ForEach(workItems, item =>
{
var progress = item.Progress as IProgress<string>();
progress.Report("Starting...");
int a = 123;
for (int i = 0; i < 200000; i++)
{
a = a + i;
Thread.Sleep(500);
}
progress.Report("Done");
}));
Console.WriteLine("Done, enabld UI controls");
}
I'd say, it is as parallel as possible. If you have 4 cores, you can run 4 threads in parallel.
If you can do stuff while waiting for the "delay", have a look into asynchronous programming (where one thread can run multiple tasks "at once", because most of them are waiting for something).
EDIT: you can also run Parallel.ForEach in its own task and await that:
private async void buttonStart_Click(object sender, EventArgs e)
{
var cells = objectListView.CheckedObjects;
if(cells != null)
{
await Task.Run( () => Parallel.ForEach( cells, c => ... ) );
}
}
I think it relies on your taskcreation-options.
TaskCreationOptions.LongRunning
Here you can find further informations:
https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskcreationoptions(v=vs.110).aspx
But you have to know, that task uses a threadpool with a finite maximum amount of threads. You can use LongRunning to signal, that this task needs a long time and should not clog your pool. I thinks it's more complex to create a long-running task, because the scheduler may create a new thread.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TaskTest
{
internal class Program
{
private static void Main(string[] args)
{
var demo = new Program();
demo.SimulateClick();
Console.ReadLine();
}
public void SimulateClick()
{
buttonStart_Click(null, null);
}
private async void buttonStart_Click(object sender, EventArgs e)
{
var tasks = new List<Task>();
for (var i = 0; i < 36; i++)
{
var taskId = i;
var t = Task.Factory.StartNew((() =>
{
Console.WriteLine($"Starting Task ({taskId})");
for (var ii = 0; ii < 200000; ii++)
{
Task.Delay(TimeSpan.FromMilliseconds(500)).Wait();
var s1 = new string(' ', taskId);
var s2 = new string(' ', 36-taskId);
Console.WriteLine($"Updating Task {s1}X{s2} ({taskId})");
}
Console.Write($"Done ({taskId})");
}),TaskCreationOptions.LongRunning);
tasks.Add(t);
}
await Task.WhenAll(tasks);
Console.WriteLine("Done, enabld UI controls");
}
}
}

How to implement robust thread monitoring in C#?

I have 2 tasks running parallelly and here is the task information.
Task 1 - Launch and run application
Task 2 - Monitor the application run duration. If it exceeds 30 mins, issue a stop command of task 1 application and restart both task.
Task 1 application bit heavy and memory leak prone during longer runs.
I am requesting, how can we implement robust threading solution for this situation.
using QuickTest;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskParallelExample
{
internal class Program
{
private static void Main(string[] args)
{
Parallel.Invoke(RunApplication, MonitorApplication);
}
private static void RunApplication()
{
Application uftInstance = new Application();
uftInstance.Launch();
QuickTest.Test uftTestInstance = uftInstance.Test;
uftInstance.Open(#"C:\Tasks\Test1");
uftInstance.Test.Run(); // It will may run more then 30 mins or less then also. It it exceeds 30 mins which is calculated from Monitor Application.
}
private static void MonitorApplication()
{
Application uftInstance = new Application();
try
{
DateTime uftTestRunMonitor = DateTime.Now;
int runningTime = (DateTime.Now - uftTestRunMonitor).Minutes;
while (runningTime <= 30)
{
Thread.Sleep(5000);
runningTime = (DateTime.Now - uftTestRunMonitor).Minutes;
if (!uftInstance.Test.IsRunning)
{
break;
}
}
}
catch (Exception exception)
{
//To-do
}
finally
{
if (uftInstance.Test.IsRunning)
{
//Assume it is still running and it is more then 30 mins
uftInstance.Test.Stop();
uftInstance.Test.Close();
uftInstance.Quit();
}
}
}
}
}
Thanks,
Ram
Could you use a CancellationTokenSource with timeout set to 30 mins?
var stopAfter30Mins = new CancellationTokenSource(TimeSpan.FromMinutes(30));
Then you would pass that to your worker method:
var task = Task.Run(() => worker(stopAfter30Mins.Token), stopAfter30Mins.Token);
...
static void worker(CancellationToken cancellation)
{
while (true) // Or until work completed.
{
cancellation.ThrowIfCancellationRequested();
Thread.Sleep(1000); // Simulate work.
}
}
Note that if the worker task cannot periodically check the cancellation status, there is NO robust way to handle task timeout.
System.Threading.Tasks.Task do the job
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task myTask = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 2000; i++)
{
token.ThrowIfCancellationRequested();
// Body of for loop.
}
}, token);
//Do sometohing else
//if cancel needed
cts.Cancel();

Executing 2 methods parallel using C#

I have a scenario to monitor the state of the ui test. If the test is running more than 30 mins, stop the test run and start with another test. Here is the code developed to simulate the same. I apologies if i am duplicating here.
Reference: execute mutiple object methods parallel
Here is the sample program that, developed in line with my requirement.I request experts to comment on my approach and suggest me the best of it.
<code>
namespace ParallelTasksExample
{
internal class Program
{
private static Stopwatch testMonitor;
private static int timeElapsed;
private static void Main(string[] args)
{
Parallel.Invoke(() => PrintNumber(), () => MonitorSequence());
}
private static void PrintNumber()
{
testMonitor = new Stopwatch();
testMonitor.Start();
for (int i = 0; i <= 10; i++)
{
System.Threading.Thread.Sleep(5000);
timeElapsed = testMonitor.Elapsed.Seconds;
Console.WriteLine("Running since :" + timeElapsed + " seconds");
}
}
private static void MonitorSequence()
{
while (timeElapsed < 25)
{
System.Threading.Thread.Sleep(2000);
Console.WriteLine("Time Elapsed :" + timeElapsed + " seconds");
}
testMonitor.Stop();
testMonitor.Reset();
Console.WriteLine("Test has taken more then 25 seconds. Closing the current test sequence initiated.");
}
}
}
</code>
I am facing an issue, when the actual code developed based on the above example.
task 1 is completed and task 2 is in progress. Meanwhile task 1 is waiting for task2 to finish. How can we make both tasks are independent?

Categories

Resources