How to perform two tasks at once - c#

I have a card in image format with the front and back side, I intend to show both sides and I created a method with thread in the period of a few seconds to show each side. The problem is that it simply shows one side and I want to see both sides within a minimum of 5 seconds
Thread t1 = new Thread(() =>
{
int numberOfSeconds = 0;
while (numberOfSeconds < 5)
{
Thread.Sleep(10);
numberOfSeconds++;
}
ImgCCF.Source = ImageSource.FromResource("Agtmovel.Img.cartFront.png");
});
Thread t2 = new Thread(() =>
{
int numberOfSeconds = 0;
while (numberOfSeconds < 8)
{
Thread.Sleep(10);
numberOfSeconds++;
}
ImgCCF.Source = ImageSource.FromResource("Agtmovel.Img.cartBack.png");
});
t1.Start();
t2.Start();
//t1.Join();
//t2.Join();

First of all avoid using directly Thread and use Task instead. They are easier to use and they better handle threads.
So you can do that like this:
private async Task FlipImagesAsync()
{
while (true)
{
await Task.Delay(5000); // I'm not entirely sure about the amount of seconds you want to wait here
Device.BeginInvokeOnMainThread(() =>
{
ImgCCF.Source = ImageSource.FromResource("Agtmovel.Img.cartFront.png");
ImgCCF.IsVisible = true;
ImgCCV.IsVisible = false;
});
await Task.Delay(8000); // I'm not entirely sure about the amount of seconds you want to wait here
Device.BeginInvokeOnMainThread(() =>
{
ImgCCV.Source = ImageSource.FromResource("Agtmovel.Img.cartBack.png");
ImgCCV.IsVisible = true;
ImgCCF.IsVisible = false;
});
}
}
Device.BeginInvokeOnMainThread is necessary so that that change is done on the UI thread.
You can call it by using Task.Run(this.FlipImagesAsync());
HIH

Related

Is there a way to reuse the same thread?

var a = 3
var b= 5
for (int i = 0; i < 10; i++)
{
var c = a + b;
Console.WriteLine(c); //This line should execute on another thread
}
How could I make the value of c print on another thread, without making a new thread each iteration? The reason I want to make it run on another thread is because writing the value of c would block the thread and make the script slower. Basically its for visual feedback
Note: I cant put a loop in the thread since the thread is only supposed to run after c is calculated
I think you need a standard Producer/Consumer pattern.
using System.Threading.Channels;
Channel<int> channel = Channel.CreateUnbounded<int>();
ChannelWriter<int> writer = channel.Writer;
ChannelReader<int> reader = channel.Reader;
var task = Task.Run(async () => await Consume());
var a = 3;
var b = 5;
for (int i = 0; i < 10; i++)
{
var c = a + b + i;
await writer.WriteAsync(c);
}
writer.Complete();
await task; // or Console.ReadKey();
async Task Consume()
{
await foreach (int x in reader.ReadAllAsync())
{
Console.WriteLine(x);
}
}
The part of the code that publishes data to the channel can also be executed in a separate thread, if necessary.
Based on the information you have given, a possible solution would be the following:
int sum = 0;
object lockObj = new object();
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
void Progress()
{
while (true)
{
// We should lock only if writting to the sum var but this is just an example.
lock (lockObj)
{
Console.WriteLine(sum);
}
// Just simple wait in order to not write constantly to the console.
Thread.Sleep(100);
// If process canceled (finished), then exit.
if (ct.IsCancellationRequested)
return;
}
}
var a = 3;
var b = 5;
Task? t = null;
for (int i = 0; i < 100000; i++)
{
// Lock to be sure that there is no concurrency issue with the Progress method if it writes to the variable.
// In our case it shouldn't be required as it only reads.
lock (lockObj)
{
sum = a + b;
}
if (t == null)
t = Task.Run(() => Progress());
}
tokenSource2.Cancel();
t.Wait();
Things to note:
We lock the access of the sum variable although it is not required as we only read from it. You can safely remove the lock statements if you do not intent to write to it from the background thread.
We use a cancellation token to indicate the termination of the thread that does the calculation (in our case the main thread). This way the other thread will terminate correctly and it will not end up running an endless loop.
We use a Task.Wait() after we end our calculation. If we don't do it, the console app will instantly kill the background thread and we might not get results displayed on the screen.

C# Multithreading with slots

I have this function which checks for proxy servers and currently it checks only a number of threads and waits for all to finish until the next set is starting. Is it possible to start a new thread as soon as one is finished from the maximum allowed?
for (int i = 0; i < listProxies.Count(); i+=nThreadsNum)
{
for (nCurrentThread = 0; nCurrentThread < nThreadsNum; nCurrentThread++)
{
if (nCurrentThread < nThreadsNum)
{
string strProxyIP = listProxies[i + nCurrentThread].sIPAddress;
int nPort = listProxies[i + nCurrentThread].nPort;
tasks.Add(Task.Factory.StartNew<ProxyAddress>(() => CheckProxyServer(strProxyIP, nPort, nCurrentThread)));
}
}
Task.WaitAll(tasks.ToArray());
foreach (var tsk in tasks)
{
ProxyAddress result = tsk.Result;
UpdateProxyDBRecord(result.sIPAddress, result.bOnlineStatus);
}
tasks.Clear();
}
This seems much more simple:
int numberProcessed = 0;
Parallel.ForEach(listProxies,
new ParallelOptions { MaxDegreeOfParallelism = nThreadsNum },
(p)=> {
var result = CheckProxyServer(p.sIPAddress, s.nPort, Thread.CurrentThread.ManagedThreadId);
UpdateProxyDBRecord(result.sIPAddress, result.bOnlineStatus);
Interlocked.Increment(numberProcessed);
});
With slots:
var obj = new Object();
var slots = new List<int>();
Parallel.ForEach(listProxies,
new ParallelOptions { MaxDegreeOfParallelism = nThreadsNum },
(p)=> {
int threadId = Thread.CurrentThread.ManagedThreadId;
int slot = slots.IndexOf(threadId);
if (slot == -1)
{
lock(obj)
{
slots.Add(threadId);
}
slot = slots.IndexOf(threadId);
}
var result = CheckProxyServer(p.sIPAddress, s.nPort, slot);
UpdateProxyDBRecord(result.sIPAddress, result.bOnlineStatus);
});
I took a few shortcuts there to guarantee thread safety. You don't have to do the normal check-lock-check dance because there will never be two threads attempting to add the same threadid to the list, so the second check will always fail and isn't needed. Secondly, for the same reason, I don't believe you need to ever lock around the outer IndexOf either. That makes this a very highly efficient concurrent routine that rarely locks (it should only lock nThreadsNum times) no matter how many items are in the enumerable.
Another solution is to use a SemaphoreSlim or the Producer-Consumer Pattern using a BlockinCollection<T>. Both solution support cancellation.
SemaphoreSlim
private async Task CheckProxyServerAsync(IEnumerable<object> proxies)
{
var tasks = new List<Task>();
int currentThreadNumber = 0;
int maxNumberOfThreads = 8;
using (semaphore = new SemaphoreSlim(maxNumberOfThreads, maxNumberOfThreads))
{
foreach (var proxy in proxies)
{
// Asynchronously wait until thread is available if thread limit reached
await semaphore.WaitAsync();
string proxyIP = proxy.IPAddress;
int port = proxy.Port;
tasks.Add(Task.Run(() => CheckProxyServer(proxyIP, port, Interlocked.Increment(ref currentThreadNumber)))
.ContinueWith(
(task) =>
{
ProxyAddress result = task.Result;
// Method call must be thread-safe!
UpdateProxyDbRecord(result.IPAddress, result.OnlineStatus);
Interlocked.Decrement(ref currentThreadNumber);
// Allow to start next thread if thread limit was reached
semaphore.Release();
},
TaskContinuationOptions.OnlyOnRanToCompletion));
}
// Asynchronously wait until all tasks are completed
// to prevent premature disposal of semaphore
await Task.WhenAll(tasks);
}
}
Producer-Consumer Pattern
// Uses a fixed number of same threads
private async Task CheckProxyServerAsync(IEnumerable<ProxyInfo> proxies)
{
var pipe = new BlockingCollection<ProxyInfo>();
int maxNumberOfThreads = 8;
var tasks = new List<Task>();
// Create all threads (count == maxNumberOfThreads)
for (int currentThreadNumber = 0; currentThreadNumber < maxNumberOfThreads; currentThreadNumber++)
{
tasks.Add(
Task.Run(() => ConsumeProxyInfo(pipe, currentThreadNumber)));
}
proxies.ToList().ForEach(pipe.Add);
pipe.CompleteAdding();
await Task.WhenAll(tasks);
}
private void ConsumeProxyInfo(BlockingCollection<ProxyInfo> proxiesPipe, int currentThreadNumber)
{
while (!proxiesPipe.IsCompleted)
{
if (proxiesPipe.TryTake(out ProxyInfo proxy))
{
int port = proxy.Port;
string proxyIP = proxy.IPAddress;
ProxyAddress result = CheckProxyServer(proxyIP, port, currentThreadNumber);
// Method call must be thread-safe!
UpdateProxyDbRecord(result.IPAddress, result.OnlineStatus);
}
}
}
If I'm understanding your question properly, this is actually fairly simple to do with await Task.WhenAny. Basically, you keep a collection of all of the running tasks. Once you reach a certain number of tasks running, you wait for one or more of your tasks to finish, and then you remove the tasks that were completed from your collection and continue to add more tasks.
Here's an example of what I mean below:
var tasks = new List<Task>();
for (int i = 0; i < 20; i++)
{
// I want my list of tasks to contain at most 5 tasks at once
if (tasks.Count == 5)
{
// Wait for at least one of the tasks to complete
await Task.WhenAny(tasks.ToArray());
// Remove all of the completed tasks from the list
tasks = tasks.Where(t => !t.IsCompleted).ToList();
}
// Add some task to the list
tasks.Add(Task.Factory.StartNew(async delegate ()
{
await Task.Delay(1000);
}));
}
I suggest changing your approach slightly. Instead of starting and stopping threads, put your proxy server data in a concurrent queue, one item for each proxy server. Then create a fixed number of threads (or async tasks) to work on the queue. This is more likely to provide smooth performance (you aren't starting and stopping threads over and over, which has overhead) and is a lot easier to code, in my opinion.
A simple example:
class ProxyChecker
{
private ConcurrentQueue<ProxyInfo> _masterQueue = new ConcurrentQueue<ProxyInfo>();
public ProxyChecker(IEnumerable<ProxyInfo> listProxies)
{
foreach (var proxy in listProxies)
{
_masterQueue.Enqueue(proxy);
}
}
public async Task RunChecks(int maximumConcurrency)
{
var count = Math.Max(maximumConcurrency, _masterQueue.Count);
var tasks = Enumerable.Range(0, count).Select( i => WorkerTask() ).ToList();
await Task.WhenAll(tasks);
}
private async Task WorkerTask()
{
ProxyInfo proxyInfo;
while ( _masterList.TryDequeue(out proxyInfo))
{
DoTheTest(proxyInfo.IP, proxyInfo.Port)
}
}
}

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");
}
}
}

Long running Process using Task objects and a Monitor Thread

I am attempting to monitor a long running process. Right now the process created new Task objects for all the small pieces, but I need some way to monitor their progress to send status to a UI.
ExecutionContext ctx = new ExecutionContext()
{
Result = result,
LastCount = result.Values.Count
};
Task t = Task.Factory.StartNew(() =>
{
foreach (var dataSlice in dataObjects)
{
Task.Factory.StartNew(() =>
{
// Do Some Work
}, TaskCreationOptions.AttachedToParent);
}
});
ctx.ParentTask = t;
Task monitor = Task.Factory.StartNew( () =>
{
ctx.LastCount = ctx.Result.Values.Count;
}, TaskCreationOptions.LongRunning);
My problem, or perhaps question is, if I force my monitor task to wait (via a SpinWait or Sleep) will it possibly lock part of the Tasks created above it? I need the monitor to check status every now and then, but I don't want it's wait condition to kill another task that needs to run.
EDIT:
So I found an interesting approach that's very similar to what Hans suggested in the comments below. It comes in two pieces. One Task to happen multiple times in the middle, and one completion task to do the final clean-up. Still in testing, but it looks promising.
Here's what it looks like:
Task t = new Task(() =>
{
int i = 0;
for (int j = 0; j < 200; j++)
{
foreach (var session in sessions)
{
Task work = action.Invoke(SomeParameter);
if (i == 50 || i == 0)
{
work.ContinueWith(task => Task.Factory.StartNew(UpdateAction));
i = 1;
}
else
{
i++;
}
}
}
});
ctx.ParentTask = t;
t.ContinueWith(CompletionAction => Task.Factory.StartNew(() => CompleteExecution(SomeParameter)));
t.Start();

How to properly wait for multiple threads that call Dispatcher.Invoke to finish in WPF application

I have a WPF application that kicks off 3 threads and needs to wait for them to finish. I have read many posts here that deal with this but none seem to address the situation where the thread code calls Dispatcher.Invoke or Dispatcher.BeginInvoke. If I use the thread's Join() method or a ManualResetEvent, the thread blocks on the Invoke call. Here's a simplified code snippet of an ugly solution that seems to work:
class PointCloud
{
private Point3DCollection points = new Point3DCollection(1000);
private volatile bool[] tDone = { false, false, false };
private static readonly object _locker = new object();
public ModelVisual3D BuildPointCloud()
{
...
Thread t1 = new Thread(() => AddPoints(0, 0, 192));
Thread t2 = new Thread(() => AddPoints(1, 193, 384));
Thread t3 = new Thread(() => AddPoints(2, 385, 576));
t1.Start();
t2.Start();
t3.Start();
while (!tDone[0] || !tDone[1] || !tDone[2])
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
Thread.Sleep(1);
}
...
}
private void AddPoints(int scanNum, int x, int y)
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
z = FindZ(x, y);
if (z == GOOD_VALUE)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
Point3D newPoint = new Point3D(x, y, z);
lock (_locker)
{
points.Add(newPoint);
}
}
);
}
}
}
tDone[scanNum] = true;
}
}
from the main WPF thread...
PointCloud pc = new PointCloud();
ModelVisual3D = pc.BuildPointCloud();
...
Any ideas about how to improve this code would be much appreciated. It seems like this should be a very common problem, but I can't seem to find it properly addressed anywhere.
Assuming you can use .NET 4, I'm going to show you how to do this in a much cleaner way that avoids sharing mutable state across threads (and thus, avoids locking).
class PointCloud
{
public Point3DCollection Points { get; private set; }
public event EventHandler AllThreadsCompleted;
public PointCloud()
{
this.Points = new Point3DCollection(1000);
var task1 = Task.Factory.StartNew(() => AddPoints(0, 0, 192));
var task2 = Task.Factory.StartNew(() => AddPoints(1, 193, 384));
var task3 = Task.Factory.StartNew(() => AddPoints(2, 385, 576));
Task.Factory.ContinueWhenAll(
new[] { task1, task2, task3 },
OnAllTasksCompleted, // Call this method when all tasks finish.
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()); // Finish on UI thread.
}
private void OnAllTasksCompleted(Task<List<Point3D>>[] completedTasks)
{
// Now that we've got our points, add them to our collection.
foreach (var task in completedTasks)
{
task.Result.ForEach(point => this.points.Add(point));
}
// Raise the AllThreadsCompleted event.
if (AllThreadsCompleted != null)
{
AllThreadsCompleted(this, EventArgs.Empty);
}
}
private List<Point3D> AddPoints(int scanNum, int x, int y)
{
const int goodValue = 42;
var result = new List<Point3D>(500);
var points = from pointX in Enumerable.Range(0, x)
from pointY in Enumerable.Range(0, y)
let pointZ = FindZ(pointX, pointY)
where pointZ == goodValue
select new Point3D(pointX, pointX, pointZ);
result.AddRange(points);
return result;
}
}
Consumption of this class is easy:
// On main WPF UI thread:
var cloud = new PointCloud();
cloud.AllThreadsCompleted += (sender, e) => MessageBox.Show("all threads done! There are " + cloud.Points.Count.ToString() + " points!");
Explanation of this technique
Think about threading differently: instead of trying to synchronize thread access to shared data (e.g. your point list), instead do heavy lifting on the background thread but don't mutate any shared state (e.g. don't add anything to the points list). For us, this means looping over X and Y and finding Z, but not adding them to the points list in the background thread. Once we've created the data, let the UI thread know we're done and let him take care of adding the points to the list.
This technique has the advantage of not sharing any mutable state -- only 1 thread accesses the points collection. It also has the advantage of not requiring any locks or explicit synchronization.
It has another important characteristic: your UI thread won't block. This is generally a good thing, you don't want your app to appear frozen. If blocking the UI thread is a requirement, we'd have to rework this solution a bit.

Categories

Resources