How do I reduce integer A when integer B increments? - c#

I am generally pretty new to C# and coding in general.
Basically, this is what I have.
public bool TimeLeft;
public void Process()
{
int B = (int)Game.LocalPlayer.Character.TravelDistanceTo(spawnPoint) * 3; // An integer based on the distance of the character to a Vector3(spawnPoint).
while (TimeLeft)
{
int A = Game.GameTime / 1000; //GameTime is time lapsed in game in milliseconds.
}
}
But this is where my brain fries. Let's assume int B is 150.
How would I go about do reduce int B by 1 every time int A increases by 1? This happens within a loop.
I declare int B outside of the loop, and A inside because it needs to update every tick. TimeLeft is set somewhere else.

You have to keep track of the value of A. When you poll A anew you store the value in another variable. Then you can compute the difference and decrease B by this difference. Pseudocode:
int A = ...
int B = ...
while(...)
{
int A_new = ...
B -= A_new - A;
}

You need to define the values outside of the loop, inside the loop should only be the processing taking place. (Like Adok has mentioned)
I'd also say that while (true) is not a good practise of a general processing loop, unless you're making sure the whole program is defined within that loop.
Some game studios have a certain "Init" function, and an "Update" function, the init will happen when the game starts up the first time, and update will always be repeated like a loop after the init has been triggered. The benefit of using Update over a personal while loop is that it won't miss out out on other looping functions like Drawing
With understanding the difference between initialising and updating, It would be easier to understand a countdown like this:
In Init:
//defining 2 values to count down, one that decreases, and one that sets the value back to default.
int A = 150;
int Amax = A;
In Update:
if (A > 0)
{
A -= 1; //decrease the value if it's not at 0
}
else
{
//trigger an activity that happens when A reaches 0
//reset the timer
A = Amax;
}

Related

C# - multiple thread start one thread

I have 3 threads in 3 classes running in parallel. Each of them, increase Pos or Neg of the Fourthclass by "1". After 3 threads are done, if Fourclass.Pos > Fourclass.Neg, it will run Terminal4.
Q: How can i run the Terminal4 only 1 time. Because putting Fourthclass.Terminal4(); in each Terminal1-2-3 will run the Terminal4 3 times.
Here is what i have done:
public class Firstclass
{
static int Pos = 1;
static int Neg = 0;
public static void Terminal1()
{
if (Pos > Neg)
{
Fourthclass.Pos += 1;
// Fourthclass.Terminal4();
}
}
}
public class Secondclass
{
static int Pos = 1;
static int Neg = 0;
public static void Terminal2()
{
if (Pos > Neg)
{
Fourthclass.Pos += 1;
// Fourthclass.Terminal4();
}
}
}
public class Thirdclass
{
static int Pos = 1;
static int Neg = 0;
public static void Terminal3()
{
if (Pos > Neg)
{
Fourthclass.Neg += 1;
// Fourthclass.Terminal4();
}
}
}
public static class Fourthclass
{
public static int Pos = 0;
public static int Neg = 0;
public static void Terminal4()
{
if (Pos > Neg)
{
Console.WriteLine("Pos = {0} - Neg = {1}", Pos, Neg);
Console.WriteLine();
}
else { Console.WriteLine("fail"); }
}
}
class Program
{
static void Main(string[] args)
{
Thread obj1 = new Thread(new ThreadStart(Firstclass.Terminal1));
Thread obj2 = new Thread(new ThreadStart(Secondclass.Terminal2));
Thread obj3 = new Thread(new ThreadStart(Thirdclass.Terminal3));
obj1.Start();
obj2.Start();
obj3.Start();
}
}
Original Answer
By the by... these increments are not thread safe, they may suffer the ABA problem and that is ignoring thread visibility problems.
For that problem, please use Interloked. Interlocked.Increment and Interlocked.Decrement will take care of it.
Now, for making a code block run only once, keep an int variable that will be 1 if it did run, and 0 if it did not. Then use Interlocked.CompareExchange:
int didrun;
// ...
if (Interlocked.CompareExchange(ref didrun, 1, 0) == 0)
{
// code here will only run once, until you put didrun back to 0
}
There are other ways, of course. This one is just very versatile.
Addendum: Ok, what it does...
Interlocked.CompareExchange will look at the value of the passed variable (didrun) compare it to the second parameter (0) and if it matches, it will change the variable to the value of first parameter (1) [Since it may change the variable, you have to pass it by ref]. The return value is what it found in the variable.
Thus, if it returns 0, you know it found 0, which means that it did update the value to 1. Now, the next time this piece of code is called, the value of the variable is 1, so Interlocked.CompareExchange returns 1 and the thread does not enter the block.
Ok, why do not use a bool instead? Because of thread visibility. A thread may change the value of the variable, but this update could happen in CPU cache only, and not be visible to other threads... Interlocked gets around of that problem. Just use Interlocked. And MSDN is your friend.
That will work regardless if you are using ThreadPool, Task or async/await or just plain old Threads as you do. I mention that because I would like to suggest using those...
Sneaky link to Threading in C#.
Extended Answer
In comment, you ask about a different behavior:
The Terminal4 has cooldown until the next run
Well, if there is a cool down (which I understand as a period) you do not only need to store whatever or not the code did run, but also when was the last time it did.
Now, the conditional cannot be just "run only if it has not run yet" but instead "run if it has not run yet or if the period from the last time it ran to now is greater than the cool down".
We have to check multiple things, that is a problem. Now the check will no longer be atomic (from the Latin atomus which means indivisible, from a- "not" + tomos "a cutting, slice, volume, section").
That is relevant because if the check is not atomic, we are back to the ABA problem.
I will use this case to explain the ABA problem. If we encode the following:
1. Check if the operation has not run (if it has not go to 4)
2. Get the last time it ran
3. Compute the difference from the last run to now (exit if less than cool down)
4. Update the last run time to now
5. Run code
Two threads may do the following:
|
t Thread1: Check if the operation has not run (it has)
i Thread2: Check if the operation has not run (it has)
m Thread2: Get the last time it ran
e Thread1: Get the last time it ran
| Thread1: Compute the difference from the last run to now (more than cool down)
v Thread2: Compute the difference from the last run to now (more than cool down)
Thread2: Update the last run time to now
Thread2: Run code
Thread1: Update the last run time to now
Thread1: Run code
As you see, they both Run code.
What we need is a way to check and update in a single atomic operation, that way the act of checking will alter the result of the other thread. That is what we get with Interlocked.
How Interlocked manages to do that is beyond the scope of the question. Suffice to say that there are some special CPU instructions for that.
The new pattern I suggest is the following (pseudocode):
bool canRun = false;
DateTime lastRunCopy;
DateTime now = DateTime.Now;
if (try to set lastRun to now if lastRun is not set, copy lastRun to lastRunCopy)
{
// We set lastRun
canRun = true;
}
else
{
if ((now - lastRunCopy) < cooldown)
{
if (try to set lastRun to now if lastRun = lastRunCopy, copy lastRun to lastRunCopy)
{
// we updated it
canRun = true;
}
}
else
{
// Another thread got in
}
}
if (canRun)
{
// code here will only run once per cool down
}
Notice I have expressed the operations in terms of "try to set X to Y if X is Z, copy X to W" which is how Interlocked.CompareExchange works.
There is a reason I left that in pseudo code, and that is that DateTime is not an atomic type.
In order to make the code work we will have to use DateTime.Ticks. For an unset value we will use 0 (00:00:00.0000000 UTC, January 1, 0001), which is something you have to worry about for a cool down greater than a couple of millennia.
In addition, of course, we will use the overload of Interlocked.CompareExchange that takes long because DateTime.Ticks is of that type.
Note: Ah, we will use TimeSpan.Ticks for the cool down.
The code is as follows:
long lastRun = 0;
long cooldown = TimeSpan.FromSeconds(1).Ticks; // Or whatever, I do not know.
// ...
bool canRun = false;
long lastRunCopy = 0;
long now = DateTime.Now.Ticks;
lastRunCopy = Interlocked.CompareExchange(ref lastRun, now, 0);
if (lastRunCopy == 0)
{
// We set lastRun
canRun = true;
}
else
{
if ((now - lastRunCopy) < cooldown)
{
if (Interlocked.CompareExchange(ref lastRun, now, lastRunCopy) == lastRunCopy)
{
// we updated it
canRun = true;
}
else
{
// Another thread got in
}
}
}
if (canRun)
{
// code here will only run once per cooldown
}
Alternatively, if you want to boil it down to a single conditional:
long lastRun = 0;
long cooldown = TimeSpan.FromSeconds(1).Ticks; // Or whatever, I do not know.
// ...
long lastRunCopy;
var now = DateTime.Now.Ticks;
if
(
(lastRunCopy = Interlocked.CompareExchange(ref lastRun, now, 0)) == 0
|| now - lastRunCopy < cooldown
&& Interlocked.CompareExchange(ref lastRun, now, lastRunCopy) == lastRunCopy
)
{
// code here will only run once per cooldown
}
As I said, Interlocked.CompareExchange is versatile. Although, as you can see, you still need to think around the requirements.

Progress bar withing a foreach loop

I have a method that iterates through an array of music notes and plays them one after the other. I have created a progress bar that will show the status of the foreach loop.
The problem is that the progress bar is not filling up to 100% but approximately till 85%. I have also noted that the progress bar is progressing roughly, I think that this could be because the steps are large. Any ideas on how can I optimize this progress bar, pb is my instance of the progress bar, Thanks
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(CountTotalDuration()); //Total lenght of the full song.
pb.Step = Convert.ToInt32(CountTotalDuration()) / Convert.ToInt32(ListSize()); //Total lenght of each note making up the song.
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
pb.PerformStep();
}
}
Your issue is from rounding errors in your steps. Lets look at a simple example, say you have a CountTotalDuration() of 100 and a ListSize() of 7
because you have two integer numbers / does integer division and throws away any remainder so 100 / 7 equals 14 (instead of 14.285714 with 285714 repeating). That makes your step size 14, so after doing 7 steps your total value you have reached is 98 and you would see 98% on the toolbar.
Since CountTotalDuration() appears to be the sum of NoteDuration the way to fix this is to not use equal step sizes each step. Instead, just set the max to the total duration and increment the bar by the tote duration. This will make the bar jump in proportion to the position in the song based on note length.
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(CountTotalDuration()); //Total lenght of the full song.
int currentCount = 0; //Initialize our counter to 0.
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
//Increment the counter proportional to the length of the note.
currentCount += m.NoteDuration;
//Set the progress bar using our calculated position.
pb.Value = currentCount;
}
}
You still are going to have big jumps when long notes play, the only way to solve that is not use Thread.Sleep(m.NoteDuration*100); and instead use multiple shorter pauses and update the bar in between those pauses. Also Thread.Sleep may not be the best way to pause the loop, but I don't know what the best alternative to use instead would be, it depends on a lot of details which you have not shared with us.
You could also have similar behavior to your old method and have the note jump by 1 for each note played and just make the bar's maximum equal to the number of notes you will play.
public void PlayAll()
{
pb.Maximum = list.Length; //Or equivalent, perhaps ListSize()?
pb.Step = 1;
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
pb.PerformStep();
}
}
This will give you more even jumps per note but if the song is only a few notes long those even jumps could still be very large.
it sounds strange, I didn't find the problem, but I suggest you can try as this:
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(ListSize()); //Total lenght of the full song.
pb.Step = 1;
int i = 1;
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration * 100);
pb.Value = i++;
}
}
further more, maybe you should use multithreading to improve the user experience, because Thread.Sleep() makes the form like dead.

Algorithm to update average transfer rate on-the-go with C#

I have a lengthy method that writes data into a database. It is called repeatedly. I also maintain the counter of records written so far, as well as the total number of records that need to be written as such:
private int currentCount;
private int totalCount;
private double fAverageTransferRate;
bool processingMethod()
{
//Processes one record at a time
DateTime dtNow = DateTime.Now; //Time now
fAverageTransferRate = //?
}
I know that to calculate a transfer rate I need to take the number of records written in one second, right, but here come two questions:
How would I time my calculation exactly at 1 second mark?
And, most of all, how do I calculate an average transfer rate?
PS. I need this done, on the go, so to speak, while this method is running (and not after it is finished.)
You could think about it a different way, since what you're really interested in is the rate of processing records. Therefore, you con't need to make the calculation happen at precisely 1 second intervals. Rather, you need it happen about every second but then know exactly when it happens.
To calculate the average transfer rate, just keep a running count of the number of records you are transferring. If more than 1 second has elapsed since the last time you computed the average, its time to compute the average anew. Zero out the running count when you're done, in preparation for the next round.
Pseudo-code follows:
// somewhere outside:
int lastdonetime = 0;
int numprocessed = 0;
bool processingMethod()
{
DateTime dtNow = DateTime.Now; //Time now
if (lastdonetime == 0) lastdonetime = dtNow;
if (dtNow - lastdonetime > 1) {
fAverageTransferRate = numprocessed / (dtNow - lastdonetime);
// Do what you want with fAverageTransferRate
lastdonetime = dtNow;
numprocessed = 0;
}
}

Progress bar not updating as expected

The progress bar is going to 70 just fine. It's when I go to update it when the loop starts that the bar doesn't move.
int count = finalFiles.Length; //finalFiles in an array and it varies in size.
int current = 0;
private void uploadWorker_DoWork(object sender, DoWorkEventArgs e)
{
uploadWorker.ReportProgress(20);
DoSomeWork();
uploadWorker.ReportProgress(50);
DoMoreWork();
uploadWorker.ReportProgress(70);
foreach (string file in finalFiles)
{
current++;
doProcess();
uploadWorker.ReportProgress(current / count * 30 + 70);
}
}
Again, the problem is that the progress bar is not updating once it reaches 70. It just doesn't move. The form does not lock up by the way because I'm using background worker.
Does anyone know why that is?
You have an integer current, and an integer count. Since count is bigger, when you do the division it is always 0 (integer division) until current reaches current. You should either make count a double/decimal, or cast one of the two to a double/decimal before doing the division.
I don't know what doProcess() does, but shouldn't you increment current in your foreach?
Looks like you need some parentheses somewhere e.g.
foreach (string file in finalFiles)
{
doProcess();
uploadWorker.ReportProgress( ((current / count) * 30) + 70);
}
OK I don't know that maths you need (sorry, I'm in the middle of something else here), but I would suggest you put parentheses in the calculation, since it looks to me like that could be an issue.

Why c# doesn't preserve the context for an anonymous delegate calls?

I have the following method:
static Random rr = new Random();
static void DoAction(Action a)
{
ThreadPool.QueueUserWorkItem(par =>
{
Thread.Sleep(rr.Next(200));
a.Invoke();
});
}
now I call this in a for loop like this:
for (int i = 0; i < 10; i++)
{
var x = i;
DoAction(() =>
{
Console.WriteLine(i); // scenario 1
//Console.WriteLine(x); // scenario 2
});
}
in scenario 1 the output is: 10 10 10 10 ... 10
in scenario 2 the output is: 2 6 5 8 4 ... 0 (random permutation of 0 to 9)
How do you explain this? Is c# not supposed to preserve variables (here i) for the anonymous delegate call?
The problem here is that there is one i variable and ten instances / copies of x. Each lambda gets a reference to the single variable i and one of the instances of x. Every x is only written to once and hence each lambda sees the one value which was written to the value it references.
The variable i is written to until it reaches 10. None of the lambdas run until the loop completes so they all see the final value of i which is 10
I find this example is a bit clearer if you rewrite it as follows
int i = 0; // Single i for every iteration of the loop
while (i < 10) {
int x = i; // New x for every iteration of the loop
DoAction(() => {
Console.WriteLine(i);
Console.WriteLine(x);
});
i++;
};
DoAction spawns the thread, and returns right away. By the time the thread awakens from its random sleep, the loop will be finished, and the value of i will have advanced all the way to 10. The value of x, on the other hand, is captured and frozen before the call, so you will get all values from 0 to 9 in a random order, depending on how long each thread gets to sleep based on your random number generator.
I think you'll get the same result with java or any Object oriented Language (not sure but here it seems logical).
The scope of i is for the whole loop and the scope of x is for each occurrence.
Resharper helps you top spot this kind of problem.

Categories