Task doesn't change parameters - c#

I am playing with Task functions and found a pretty strange problem that I run Task in for loop and pass the parameters to function (i) the loop count is 100.
As I expected the output would be like this.
1
2
3
4
5
But the output I get from this function is
100
100
100
I mean it won't change to new parameters. For more details I uploaded the whole project.
Download Sample Program that I made!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
}
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => button_tast());
}
void button_tast()
{
Task[] tk =new Task[100];
for (int i = 0; i < 100; i++)
{
tk[i] = Task.Factory.StartNew(() => taskThread(i));
}
Task.WaitAll(tk);
}
void taskThread(int i){
listBox1.Items.Add(i);
}
}
}

It's because you're closing over the loop variable. You can rewrite the loop as
for (int i = 0; i < 100; i++)
{
int taskNumber = i
tk[i] = Task.Factory.StartNew(() => taskThread(taskNumber));
}
and you'll be fine

The problem is that from the point of view of the Tasks, the variable i is global, and can be modified in a non-threadsafe manner. This is easily rectified though....
for (int i = 0; i < 100; i++)
{
int localCopy = i;
tk[i] = Task.Factory.StartNew(() => taskThread(localCopy));
}

Related

I can't get this simple calculation right

I have a very small windows form application that calculates the storage cost for a warehouse depending on the amount of deliveries per year and presents the result in form of a chart.
It's doing what it's supposed to do, but there is just one little flaw.
There is 13 columns in the first bit and then there is 12 every other time.
I want it to always be 12.
I've been trying to reorder some lines of code, it looks like it's all ok, I'm probably just missing one line of code but can't figure it out
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace StorageCost
{
public partial class Form1 : Form
{
public static int throughPot = 52000;
public static int weekly = 1000;
public static int weeklyPalletCost = 180;
public static int deliveries = 2;
public int storageCost;
public static int x = 0;
public static int currentPot = throughPot / deliveries;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Calculate();
}
private void Calculate()
{
currentPot = throughPot / deliveries;
storageCost = 0;
x = 0;
chart1.Series[0].Points[0].YValues[0] = currentPot + 4000;
for (int i = 1; i < 51; i++)
{
currentPot -= weekly;
if (x>= 51 / deliveries)
{
x = 0;
currentPot = throughPot / deliveries;
}
chart1.Series[0].Points[i].YValues[0] = currentPot + 4000;
storageCost += currentPot * weeklyPalletCost;
x++;
}
cost.Text = "Total storage cost: £" + storageCost / 100;
chart1.ChartAreas[0].RecalculateAxesScale();
chart1.Update();
}
private void deliveriesUpDown_ValueChanged(object sender, EventArgs e)
{
deliveries = (int)deliveriesUpDown.Value;
Calculate();
}
}
}
this is the full code.
all I need basically is to get the same result in the beginning as from 13th column onwards
any help will be much appreciated.
thanks in advance.
It was because the first column was done outside of the for loop!
after commenting this out
//currentPot = throughPot / deliveries;
//storageCost = 0;
//x = 0;
//chart1.Series[0].Points[0].YValues[0] = currentPot + 4000;
and changing the loop to for (int i = 0; i < 51; i++)
I got it to work as expected.
Thanks #Grimm
I didn't know about this F11, F10 thing. This helped me a lot!

I try to find nearest double in Array

I try to follow the code here:
C# Finding Nearest Number in Array
but fail.
The only different from my code with the code there is in my code the MinBy is error (there is red underline) which show its an error in Visual Studio.
By the way, this is the the code that I write:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
double[] array = new double[5] { 0.25, 0.4, 0.5, 0.6, 0.7 };
double TargetNumber = Double.Parse(textBox1.Text);
var nearest = array.MinBy(x => Math.Abs((long)x - targetNumber));
label1.Text = nearest.ToString();
}
}
}
Im new with C# things. Sorry for a noob question.
Thanks in advance.
You overcomplicate things. Here is your "bread-and-butter" helper method which finds the value from array a nearest to the passed value d:
private static double? FindNearestValue(IEnumerable<double> arr, double d)
{
var minDist = double.MaxValue;
double? nearestValue = null;
foreach (var x in arr)
{
var dist = Math.Abs(x - d);
if (dist < minDist)
{
minDist = dist;
nearestValue = x;
}
}
return nearestValue;
}
To use it:
private void button1_Click(object sender, EventArgs e)
{
double[] array = new double[5] { 0.25, 0.4, 0.5, 0.6, 0.7 };
double TargetNumber = Double.Parse(textBox1.Text);
var nearest = FindNearestValue(array, TargetNumber);
label1.Text = nearest.ToString(); // nulls are printed as empty string
}
For small arrays linear search has comparable speed to the binary search. If implementing binary search is problem for you and you're new to c# (didn't get used to LINQ power) then good-ol' foreach is your friend for now.
Sometimes implementing a library to use just one method sounds a little bit like an overkill (even if MoreLINQ is an amazing library)... this code should provide you the same result without using an external library, if it's a good solution for you:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Double[] array = new Double[] { 0.25, 0.4, 0.5, 0.6, 0.7 };
Double targ = Double.Parse(textBox1.Text);
Double[] arraySorted = array.OrderBy(x => Math.Abs(x - targ)).ToArray();
Int32 idx = Array.IndexOf(array,arraySorted.First());
label1.Text = idx.ToString();
Double arrayValue = array[idx];
Int32 idxLower = 0;
Int32 idxUpper = 0;
if (targ == arrayValue)
idxLower = idxUpper = idx;
else
{
if (targ > arrayValue)
{
idxLower = idx;
idxUpper = idx + 1;
}
else
{
idxLower = idx - 1;
idxUpper = idx;
}
}
label2.Text = idxLower.ToString();
label3.Text = idxUpper.ToString();
}
}
}

Async Await Loop/Math problems

I'm making a little program to practice with WPF and Async/Await for multithreading, and what the program does is:
Find all the prime numbers between two numbers "a" and "b", and spit them out to a textbox called "Prime1".
Simultaneously in a different task, find all the prime numbers between "c" and "d", and spit them out to a textbox called "Prime2".
A button in the window will allow the user to click it, and it will keep track of how many times it has been clicked, whilst the other two tasks find prime numbers, to demonstrate asynchronous operations.
The code is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPF_Asynch_Project
{
public partial class MainWindow : Window
{
public int ClickAmount = 0;
public MainWindow()
{
InitializeComponent();
DelegationIsAwesome();
}
private void Test_Click(object sender, RoutedEventArgs e)
{
ClickAmount++;
MessageBox.Show("You clicked me " + ClickAmount.ToString() + " times!");
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
}
private async void DelegationIsAwesome()
{
Task enumtask = new Task(() => FindPrimes(100000, 100000000));
Task[] enumall = new Task[2];
enumall[0] = enumtask;
enumall[1] = new Task(() => FindPrimes2(1000, 10000));
enumall.ToList().ForEach(t => t.Start());
await Task.WhenAll(enumall).ConfigureAwait(false);
}
private void FindPrimes(long lower, long upper)
{
for (long i = lower; i < upper; i++)
{
long primeornot = 1;
for (long q = 2; q < i; q++)
{
if (i % q == 0)
{
primeornot = 0;
}
}
if (primeornot == 1)
{
System.Threading.Thread.Sleep(6);
Prime1.Dispatcher.BeginInvoke(
(Action)(()=>{ Prime1.Text += i.ToString() + ", "; }));
}
}
}
private void FindPrimes2(int lower, long upper)
{
for (int i = lower; i < upper; i++)
{
int primeornot = 1;
for (int q = 2; q < i; q++)
{
if (i % q == 0)
{
primeornot = 0;
}
}
if (primeornot == 1)
{
System.Threading.Thread.Sleep(5);
Prime2.Dispatcher.BeginInvoke(
(Action)(() => { Prime2.Text += i.ToString() + ", "; }));
}
}
}
}
}
However I get odd results. The following is a picture from the program:
Obviously the output from the prime-finding methods is incorrect. But why does it keep repeating those same numbers? It also sometimes spits out a number equal to UpperBound even though "i" should never equal or be greater than UpperBound.
What is happening to my output, and how do I fix it?
This has nothing to do with async/await, really.
You're calling BeginInvoke here:
Prime1.Dispatcher.BeginInvoke(
(Action)(()=>{ Prime1.Text += i.ToString() + ", "; }));
... and your lambda expression uses i, which means it will append the current value of i when the delegate executes. That's not necessarily the value of i when you call BeginInvoke.
If you want to capture the value (rather than the variable) you basically need to instantiate a new variable each time. You might as well do the conversion to a string:
string textToAppend = i + ", ";
// No need for braces here...
Prime1.Dispatcher.BeginInvoke((Action)(() => Prime1.Text += textToAppend));
Because you've declared the variable textToAppend inside the loop, each iteration will create a delegate capturing a separate variable.
You need to do this in both of your methods.

How do you pass a function to itself a variable number of times to form an "n level method call"?

Suppose we have the bare bones C# code for random number generation.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace theBlindPainterTester
{
public partial class Form1 : Form
{
Random randomNumber = new Random();
public Form1()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
randomNumber.Next(1, 6);
}
}
}
We could easily call Next() on itself to set the upper bound.
randomNumber.Next(1, randomNumber.Next(1, 6));
This could be referred to as a two level method call, a "random number between 1 and (a random number between 1 and 5)." Similarly we could write a three level method call.
randomNumber.Next(1, randomNumber.Next(1, randomNumber.Next(1, 6)));
How can we do this for N levels, where N is a variable not known until run time? I've attempted to mold out the logic using a recursive method, but it seems you would need to call Next() on every iteration for that to work, which requires immediate knowledge of parameters. Perhaps I'm just not thinking about it the correct way.
r = 6;
for (int k = 0; k < N; k++)
r = randomNumber.Next(1, r);
Wouldn't this work?
private int Generate(int Counter)
{
if (Counter>0)
return randomnumber.Next(1, Generate(Counter-1));
else
return randomnumber.Next(1, 6);
}

C# wpf multithreading

I want to generate 3 random number in threads then save it to list. Here's my code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.IO;
namespace Multithreading1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
List<int> myList = new List<int>();
int threadNumber = 0;
int currentRecNumber = -1;
public MainWindow()
{
InitializeComponent();
}
void ThreadHandler(int recNumber,int number)
{
Action action = null;
action = () =>
{
myList[recNumber] = number;
++currentRecNumber;
--threadNumber;
if (currentRecNumber < myList.Count)
{
++threadNumber;
Thread t = new Thread(() => GetRandomNumber(currentRecNumber));
t.Start();
}
else
if (threadNumber == 0) //finish
{
List<String> stringList = new List<String>();
for (int i = 0; i < myList.Count;i++)
{
stringList.Add(myList[i].ToString());
}
File.WriteAllLines("C:\\Users\\Public\\Documents\\MyList.txt", stringList);
System.Windows.MessageBox.Show("Finish");
}
};
this.Dispatcher.BeginInvoke(action);
}
void GetRandomNumber(int recNumber)
{
Random rnd = new Random();
int randomInt = rnd.Next(1, 13);
ThreadHandler(recNumber, randomInt);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 20; i++)
{
myList.Add(-1);
}
for (int i = 0; i < 3; i++)
{
++currentRecNumber;
++threadNumber;
Thread t = new Thread(() => GetRandomNumber(currentRecNumber));
t.Start();
}
}
}
}
The problem are:
1. Sometimes it throw ArgumentOutOfRangeException at myList[recNumber] = number;
2. If it get past (1) the resulting file still contain -1s, eg:
-1
-1
8
6
11
-1
1
3
-1
3
3
8
8
8
8
10
10
10
10
12
Anyone know what is wrong ?
Thanks in advance.
Your Dispatcher.BeginInvoke will call each action on the thread the dispatcher is associated with, so you are effectively not actually running the actions on different threads. It might be better to do as much as you can in the ThreadHandler method, and only make UI changes inside the BeginInvoke action.
Also in your button1_Click, you increment currentRecNumber before you start each thread, so that will cause the first few threads to skip the first few items in the list.
You also have a major issue because you are accessing shared variables (currentRecNumber, threadNumber, and myList) from different threads, which can cause all manner of threading issues. You need to use some sort of synchronisation to ensure that each thread is reading and writing the correct values from these variables. You can use the InterlockedIncrement and InterlockedDecrement to mitigate some of these issues, but not all of them.
I'll also point out that creating threads is expensive, it's much better to schedule the work you want doing on thread pool threads , use a BackgroundWorker, or use one of the parallelism libraries, like the Task Parallel Library or PLINQ.
I would recommend having a read of this free ebook on threading by Joe Albahari.
Thanks Matt for the ebook. It's very easy to understand. I managed to fix my code with minor addition. The key of its problem is "Lambda expressions and captured variables", so I add couple local variables to it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.IO;
namespace Multithreading1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
List<int> myList = new List<int>();
int threadNumber = 0;
int currentRecNumber = -1;
public MainWindow()
{
InitializeComponent();
}
void ThreadHandler(int recNumber,int number)
{
Action action = null;
action = () =>
{
myList[recNumber] = number;
++currentRecNumber;
--threadNumber;
int localCurrentRecNumber = currentRecNumber;
int localThreadNumber = threadNumber;
if (localCurrentRecNumber < myList.Count)
{
++threadNumber;
Thread t = new Thread(() => GetRandomNumber(localCurrentRecNumber));
t.Start();
}
else
if (localThreadNumber == 0) //finish
{
List<String> stringList = new List<String>();
for (int i = 0; i < myList.Count;i++)
{
stringList.Add(myList[i].ToString());
}
File.WriteAllLines("C:\\Users\\Public\\Documents\\MyList.txt", stringList);
System.Windows.MessageBox.Show("Finish");
}
};
this.Dispatcher.BeginInvoke(action);
}
void GetRandomNumber(int recNumber)
{
Random rnd = new Random();
int randomInt = rnd.Next(1, 13);
ThreadHandler(recNumber, randomInt);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 20000; i++)
{
myList.Add(-1);
}
for (int i = 0; i < 3; i++)
{
++currentRecNumber;
++threadNumber;
int localCurrentNumber = currentRecNumber;
Thread t = new Thread(() => GetRandomNumber(localCurrentNumber));
t.Start();
}
}
}
}

Categories

Resources