I've been struggling with Parallel.For and local variable. I'm trying to update percentages in a console app from a parallel for. I add page in multiple document and I would like an update on the percentage for each document.
Here's my attempt so far :
I'm taking the number of the line with Console.CursorTop, and I want to pass it to a method who's gonna override the line.
Loop from Program.cs
Parallel.For(0, generationFile.nbOfFile, optionsParallel,
i =>
{
string fileName = $"{tmpDirectoryPath}/{i + 1}_{guid}.pdf";
AddPage(fileName, generationFile, i);
});
The AddPage method
private static void AddPage(string fileName, GenerationFile generationFile, int i)
{
var cursorPosition = Console.CursorTop;
//Ajout des pages
for (int j = 0; j < generationFile.SizeMaxFile; j++)
{
Page page = Page.Create(outDoc, size);
AddText(outDoc, page, font, 14, i, fileName, j, generationFile.SizeMaxFile);
for (int k = 0; k < 292; k++)
{
AddImage(outDoc, page, 30, 30);
}
outDoc.Pages.Add(page);
ConsoleManager.UpdateConsole(i, j, cursorPosition, generationFile);
}
}
The UpdateConsole method
public static void UpdateConsole(int fileNumber, double progression, int cursorPosition, GenerationFile generationFile)
{
progression = (progression / 100) * generationFile.ArchiveESC;
Console.ForegroundColor = ConsoleColor.White;
Console.SetCursorPosition(0, cursorPosition);
Console.WriteLine($"\rFichier n°{fileNumber + 1}/{generationFile.SizeMaxFile} en cours de création : {progression}% ", Console.ForegroundColor);
}
I think everything works fine, except for the cursorPosition who take one value at the beginning and never change, so the same line is updated. I understand that there is something to do with local and/or shared variable, but I'm fairly new in parallel processing so even with the other threads on this topic and the MSDN, I don't understand what to do.
The way I prefer to handle progress reporting is to have all worker threads report to a shared progress field, and have a separate timer that reads this fields and reports the progress to the user. This lets me control how often progress is reported, regardless of how fast items are processed. I also want an abstraction layer that allows different ways to report progress. After all, the same method might be used from console, the UI, or not at all.
For example something like this:
public interface IMyProgress
{
void Increment(int incrementValue);
}
public sealed class MyProgress : IMyProgress, IDisposable
{
private readonly int totalItems;
private readonly Timer myTimer;
private volatile int progress;
private int lastUpdatedProgress;
public MyProgress(TimeSpan progressFrequency, int totalItems)
{
this.totalItems = totalItems;
myTimer = new Timer(progressFrequency.TotalMilliseconds);
myTimer.Elapsed += OnElapsed;
myTimer.Start();
}
private void OnElapsed(object sender, ElapsedEventArgs e)
{
var currentProgress = progress;
if (lastUpdatedProgress != currentProgress)
{
lastUpdatedProgress = currentProgress;
var percent = currentProgress * 100 / (double)totalItems;
Console.Write($"\rWork progress: {percent}%");
}
}
public void Increment(int incrementValue) => Interlocked.Add(ref progress, incrementValue);
public void Dispose() => myTimer?.Dispose();
}
This can be called from a parallel method like:
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var myWorkItems = Enumerable.Range(1, 10000).ToList();
using var progress = new MyProgress(TimeSpan.FromSeconds(1), myWorkItems.Count);
DoProcessing(myWorkItems, progress);
}
private static void DoProcessing(IEnumerable<int> items, IMyProgress progress)
{
Parallel.ForEach(items, item =>
{
Thread.Sleep(20);
progress.Increment(1);
});
}
I would be a bit careful when using carriage returns. In my experience console applications tend to be used by other programs as much as by humans, and then it is likely that the output will be redirected to a file, and that does not support carriage returns. So I would try to make the output look good.
I would avoid trying to move the cursor around. I have tried that, but the result was unsatisfactory, YMMV.
Im looking to call the same method every x seconds in my c# console app, but I also want to only call this method a certain number of times (say 5).
I need each method to run after each other (cant have them over lapping)
My biggest issue is the console app closing before being completed
The current code I have works but is kinda messy (the while loop)
static void Main(string[] args)
{
for (int t = 0; t < 3; t++)
{
InitTimer(t);
}
}
public static void InitTimer(int t)
{
Console.WriteLine("Init" + t);
int x = 0;
var timer = new System.Threading.Timer(
e => x = MyMethod(x),
null,
TimeSpan.Zero,
//delay between seconds
TimeSpan.FromSeconds(5));
//number of times called
while (x < 5)
{
}
timer.Dispose();
}
public static int MyMethod(int x)
{
Console.WriteLine("Test" + x);
//call post method
x += 1;
return x;
}
}
Is there a neater way to create the same functionality ?
I imagined the result would be a negative value, due to not locking and multiple threads sharing the same object. I have tested this many times with release and debug version, every time the result is correct. Why is it still correct?
Code :
static BankAccount ThisbankAccount = new BankAccount(10000);
public static void WithdrawMoney()
{
for(int i = 0; i < 1000; i++)
ThisbankAccount.WithdrawMoney(25);
}
static void Main(string[] args)
{
Thread client1 = new Thread(WithdrawMoney);
Thread client2 = new Thread(WithdrawMoney);
Thread client3 = new Thread(WithdrawMoney);
client1.Start();
client2.Start();
client3.Start();
client3.Join();
Console.WriteLine( ThisbankAccount.Balance);
Console.ReadLine();
}
}
public class BankAccount
{
object Acctlocker = new object();
public BankAccount(int initialAmount)
{
m_balance = initialAmount;
}
public void WithdrawMoney(int amnt)
{
// lock(Acctlocker)
// {
if (m_balance - amnt >= 0)
{
m_balance -= amnt;
}
// }
}
public int Balance
{
get
{
return m_balance;
}
}
private int m_balance;
}
Just because something works now doesn't mean it is guaranteed to work. Race conditions are hard to trigger and might take years to surface. And when they surface, they can be very hard to track down and diagnose.
To see your problem in action, change this code:
if (m_balance - amnt >= 0)
{
m_balance -= amnt;
}
to:
if (m_balance - amnt >= 0)
{
Thread.Sleep(10);
m_balance -= amnt;
}
That introduces a slow enough code path to highlight the problem really easily.
The reason you aren't spotting it with your current code is that the operations you are doing (subtraction and comparisons) are very fast. So the window for the race condition is very small - and you are lucky enough for it not to occur. But, over unlimited time, it definitely will occur.
Good day fellow developers,
I'm trying to create a Timing class in C# which can output the amount of time it takes to execute specific lines code. Here is the class that I developed so far (it is using the QueryPerformanceCounter):
class Timing
{
private long start;
private long stop;
private long frequency;
Decimal multiplier = new Decimal(1.0e9);
// Importing important DLL's that will be used
[DllImport("KERNEL32")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
// Timing constructor
public Timing()
{
if (QueryPerformanceFrequency(out frequency) == false)
{
// Frequency not supported
throw new Win32Exception();
}
}
// Method for starting the counter
public void Start()
{
QueryPerformanceCounter(out start);
}
// Method for stopping the counter
public void Stop()
{
QueryPerformanceCounter(out stop);
}
// Returns the average time between iterations in nanoseconds
public double Duration(int iterations)
{
return ((((double)(stop - start) * (double)multiplier) / (double)frequency) / iterations);
}
// Get the elapsed time between the start and the stop function in nanoseconds
public double getElapsedTime()
{
return (((double)(stop - start) * (double)multiplier) / (double)frequency);
}
}
I wanted to perform a test to see if my Timing class would print out the same amount of time when executing the same line of code five times in a row:
static void Main(string[] args)
{
runCollectionTest(1000);
runCollectionTest(1000);
runCollectionTest(1000);
runCollectionTest(1000);
runCollectionTest(1000);
while (true) ;
}
public static void runCollectionTest(int iterations)
{
Timing timer = new Timing();
timer.Start();
ArrayList list = new ArrayList();
for (int i = 0; i < iterations; i++)
{
list.Add(i);
}
timer.Stop();
Console.WriteLine("Time elapsed: " + timer.getElapsedTime() / 1000000 + " milliseconds");
}
Here is the output of the code:
Time elapsed: 0,24631157341192 milliseconds
Time elapsed: 0,0486376114202896 milliseconds
Time elapsed: 0,0620241099763327 milliseconds
Time elapsed: 0,0589005936465893 milliseconds
Time elapsed: 0,088350890469884 milliseconds
I have no idea how the first time elapse and the second one can differ that much compared to the other results.
I'm trying to create a timer in c# for an online game. All i really want is a timer that counts 60 seconds and then restarts. And let it go forever, then add a point for every time it resets...
What i've done so far is:
DateTime dateTime = DateTime.Now;
int sec = dateTime.Second;
if(sec = 1)
{
// stuff
}
The if does not loop, how do I do that? or anyone have a better idea? I'd really like one where i can change the seconds.
I think System.Threading.Timer might be useful, just set a callback that triggers after 60 seconds.
i found something related to my question and edited to what i wanted. it does what I want it to do, but does it create overflow or not, that im not sure of. Does anyone have a better idea of doing this?
using System;
namespace ticket
{
class Program
{
public static int x = 0;
static void LoopingFunction()
{
while (x <= 20)
{
int dwStartTime = System.Environment.TickCount;
while (true)
{
if (System.Environment.TickCount - dwStartTime > 100) break; //100 milliseconds
}
Console.WriteLine(x);
x++;
if (x == 20)
{
///add "stuff"
Console.WriteLine("Test");
x = 0;
}
}
}
static void Main()
{
LoopingFunction();
Console.Read();
}
}
}