for (int i = 0; i < 10; i++)
new Thread (() => Console.Write (i)).Start();
As expected the output of the above code is non-deterministic, because i variable refers to the same memory location throughout the loop’s lifetime. Therefore, each thread calls Console.Write on a variable whose value may change as it is running
However,
for (int i = 0; i < 10; i++)
{
int temp = i;
new Thread (() => Console.Write (temp)).Start();
}
Is also giving non-deterministic output! I thought variable temp was local to each loop iteration. Therefore, each thread captured a different memory location and there should have been np problem.
Your program should have 10 lambdas, each writing one of the digits from 0 to 9 to the console. However, there's no guarantee that the threads will execute in order.
Is also giving non-deterministic output!
No, its not. I have checked ten times your first code (had repeating numbers) and the second (had not).
So it all works fine. Just as it should.
The second code snippet should be deterministic in the sense that each thread eventually writes its temp, and all their temps will differ.
However, it does not guarantee that threads will be scheduled for execution in the order of their creation. You'll see all possible temps, but not necessarily in ascending order.
Here is the proof that OP is right and both pieces of his code are incorrect.
And there is also a solution with proof also.
However need to note that 'non-deterministic' means that the threads receive wrong parameter. The order will be never guaranteed.
The code below examines second piece of OP code and demonstrates that it is working as expected..
I am storing the pair (thread identity, parameter) and then print it to compare with the thread output to prove the pairs aren't changed. I also added few hundreds millisecond random sleep so the for index should obviously change at those times.
Dictionary<int, int> hash = new Dictionary<int, int>();
Random r = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < 10; i++)
{
int temp = i;
var th = new Thread(() =>
{
Thread.Sleep(r.Next(9) * 100);
Console.WriteLine("{0} {1}",
Thread.CurrentThread.GetHashCode(), temp);
});
hash.Add(th.GetHashCode(), temp);
th.Start();
}
Thread.Sleep(1000);
Console.WriteLine();
foreach (var kvp in hash)
Console.WriteLine("{0} {1}", kvp.Key, kvp.Value);
Related
I have question about difference of following code:
I will show the code first used with normal for loop.
Guesser class contructor starts mixing the character array and startBruteForce calls the function which permutates it in the key with the appropriate length that is matched to the private password. To every new key, I setted Console.Write (key);
And results was different in each loop.
DateTime timeStarted = DateTime.Now;
Console.WriteLine("Start BruteForce - {0}", timeStarted.ToString());
for (int i = 0; i < Environment.ProcessorCount; i++)
{
Guesser guesser = new Guesser();
Thread thread = new Thread(guesser.startBruteForce);
thread.Start();
}
while (!Guesser.isMatched) ;
Console.WriteLine("Time passed: {0}s", DateTime.Now.Subtract(timeStarted).TotalSeconds);
and Parallel.For
DateTime timeStarted = DateTime.Now;
Console.WriteLine("Start BruteForce - {0}", timeStarted.ToString());
Parallel.For(0, Environment.ProcessorCount , (i) =>
{
Guesser guesser = new Guesser();
guesser.startBruteForce();
});
while (!Guesser.isMatched) ;
Console.WriteLine("Time passed: {0}s", DateTime.Now.Subtract(timeStarted).TotalSeconds);
In ParallelFor it was something like: a,b,c,d,e,f...ab,ac,ad...
While in normal foor loop it was much more permutated for ex: b,r,1,a,k,b,ed
It look like ParrarelFor created only one thread.
Normal for loop performs the brute-force algorithm faster than Parallel.For loop.
My question is why this is happening.
Another thing that interests me is why if I will narrow the number of iterations to Environment.ProcessorCount/2both algorithms execution time are faster than just iterted with unchangedEnvironment.ProcessorCount.
I have coded a C# Windows Form Application where there are two nested for loops like below:
List<int> My_LIST = new List<int>();
List<string> RESULT_LIST = new List<string>();
int[] arr = My_LIST.ToArray();
for (int i = 0; i < arr.Length; i++)
{
int counter = i;
for (int j = 1; j <= arr.Length; j++)
{
if (counter == arr.Length)
{
counter = 0;
}
sb.Append(arr[counter].ToString());
RESULT_LIST.Add(sb.ToString());
counter++;
}
sb.Clear();
}
I used this code to take any combination of characters that are inside my array.
When the array's length gets 3000 or more the program gets stuck. How can I fix this issue?
Because based on my application's needs the size of my array must be large.
First, I had used a normal string to get the combinations and my code was like below:
string s = "";
instead of this:
StringBuilder sb = new StringBuilder();
I thought that there may be a problem with the normal string's maximum length and therefore I changed it to StringBuilder but the problem was not fixed.
Is this problem solvable or I should use an alternative?
your program is not getting stuck, rather it's taking a long time to finish due to it only running on a single thread.
you may want to use Parallel.For which its iterations can run in parallel.
I would first suggest parallelising the outer for loop and then test if there are any performance improvements if not then also parallelise the inner loop. In the majority of cases parallelising the outer for loop can prove sufficient.
Also, note that using a StringBuilder as an accumulator and then performing sb.Append(arr[counter].ToString()); inside the loop is sub-optimal. Don't call toString at all, just append.
However, when performing parallel processing keep in mind that StringBuilder is not thread-safe, therefore, you're better off using a String rather than trying to introduce locking or anything of that sort to retain the StringBuilder.
Finally, you'll need to be cautious in regards to shared state, and therefore I'd recommend you do some research in terms of what to take into account when performing parallel processing.
This question already has answers here:
creating new threads in a loop
(2 answers)
Closed 9 years ago.
In C#, if I execute
for (int i = 0;i < 10;i++)
new Thread(() => Console.Write(i)).Start();
I will possibly get 0223557799, that's strange, since i is a int, I think it should be copied before the thread starts.
Closures are your problem here.
Basically, instead of grabbing the value when you create the lambda (in the loop), it grabs it when it needs it. And computers are so fast that by the time that happens, it's already changed. It can't go through the whole loop, but it goes through some of it.
Here's a fix:
for (int i = 0; i < 10; i++)
{
var n = i;
new Thread(() => Console.Write(n)).Start();
}
Because Start() returns immediately, i++ happens before the thread gets a chance to print i to the console. I believe that a workaround is to create a local copy of the int, then print that:
for (int i = 0;i < 10;i++) {
int j = i;
new Thread(() => Console.Write(j)).Start();
}
What basically is happening is this:
You want to start a thread that prints the value of i.
The thread starts.
The code operating in the thread gets the value if i. Note that the value of i can be changed by now.
The value of i gets printed. But no guarantees to get a logical output.
Copy the value of i into another variable first and then print that value. The other answers provide enough samplecode.
Your lambda will be translated into set of the method and context class which will handle a refference to the i.
I would use the built in .NET parallelism support Task Parallelism
You won't have to worry about managing the threads it's done for you.
Example your code converted to the Parallelism libraries.
Parallel.For(0, 10, (i, state) =>
{
Console.WriteLine(i);
});
I wrote this experiment to demonstrate to someone that accessing shared data conccurently with multiple threads was a big no-no. To my surprise, regardless of how many threads I created, I was not able to create a concurrency issue and the value always resulted in a balanced value of 0. I know that the increment operator is not thread-safe which is why there are methods like Interlocked.Increment() and Interlocked.Decrement() (also noted here Is the ++ operator thread safe?).
If the increment/decrement operator is not thread safe, then why does the below code execute without any issues and results to the expected value?
The below snippet creates 2,000 threads. 1,000 constantly incrementing and 1,000 constantly decrementing to insure that the data is being accessed by multiple threads at the same time. What makes it worse is that in a normal program you would not have nearly as many threads. Yet despite the exaggerated numbers in an effort to create a concurrency issue the value always results in being a balanced value of 0.
static void Main(string[] args)
{
Random random = new Random();
int value = 0;
for (int x=0; x<1000; x++)
{
Thread incThread = new Thread(() =>
{
for (int y=0; y<100; y++)
{
Console.WriteLine("Incrementing");
value++;
}
});
Thread decThread = new Thread(() =>
{
for (int z=0; z<100; z++)
{
Console.WriteLine("Decrementing");
value--;
}
});
incThread.Start();
decThread.Start();
}
Thread.Sleep(TimeSpan.FromSeconds(15));
Console.WriteLine(value);
Console.ReadLine();
}
I'm hoping someone can provide me with an explanation so that I know that all my effort into writing thread-safe software is not in vain, or perhaps this experiment is flawed in some way. I have also tried with all threads incrementing and using the ++i instead of i++. The value always results in the expected value.
You'll usually only see issues if you have two threads which are incrementing and decrementing at very close times. (There are also memory model issues, but they're separate.) That means you want them spending most of the time incrementing and decrementing, in order to give you the best chance of the operations colliding.
Currently, your threads will be spending the vast majority of the time sleeping or writing to the console. That's massively reducing the chances of collision.
Additionally, I'd note that absence of evidence is not evidence of absence - concurrency issues can indeed be hard to provoke, particularly if you happen to be running on a CPU with a strong memory model and internally-atomic increment/decrement instructions that the JIT can use. It could be that you'll never provoke the problem on your particular machine - but that the same program could fail on another machine.
IMO these loops are too short. I bet that by the time the second thread starts the first thread has already finished executing its loop and exited. Try to drastically increase the number of iterations that each thread executes. At this point you could even spawn just two threads (remove the outer loop) and it should be enough to see wrong values.
For example, with the following code I'm getting totally wrong results on my system:
static void Main(string[] args)
{
Random random = new Random();
int value = 0;
Thread incThread = new Thread(() =>
{
for (int y = 0; y < 2000000; y++)
{
value++;
}
});
Thread decThread = new Thread(() =>
{
for (int z = 0; z < 2000000; z++)
{
value--;
}
});
incThread.Start();
decThread.Start();
incThread.Join();
decThread.Join();
Console.WriteLine(value);
}
In addition to Jon Skeets answer:
A simple test that at least on my litte Dual Core shows the problem easily:
Sub Main()
Dim i As Long = 1
Dim j As Long = 1
Dim f = Sub()
While Interlocked.Read(j) < 10 * 1000 * 1000
i += 1
Interlocked.Increment(j)
End While
End Sub
Dim l As New List(Of Task)
For n = 1 To 4
l.Add(Task.Run(f))
Next
Task.WaitAll(l.ToArray)
Console.WriteLine("i={0} j={1}", i, j)
Console.ReadLine()
End Sub
i and j should both have the same final value. But they dont have!
EDIT
And in case you think, that C# is more clever than VB:
static void Main(string[] args)
{
long i = 1;
long j = 1;
Task[] t = new Task[4];
for (int k = 0; k < 4; k++)
{
t[k] = Task.Run(() => {
while (Interlocked.Read(ref j) < (long)(10*1000*1000))
{
i++;
Interlocked.Increment(ref j);
}});
}
Task.WaitAll(t);
Console.WriteLine("i = {0} j = {1}", i, j);
Console.ReadLine();
}
it isnt ;)
The result: i is around 15% (percent!) lower than j. ON my machine. Having an eight thread machine, probabyl might even make the result more imminent, because the error is more likely to happen if several tasks run truly parallel and are not just pre-empted.
The above code is flawed of course :(
IF a task is preempted, just AFTER i++, all other tasks continue to increment i and j, so i is expected to differ from j, even if "++" would be atomic. There a simple solution though:
static void Main(string[] args)
{
long i = 0;
int runs = 10*1000*1000;
Task[] t = new Task[Environment.ProcessorCount];
Stopwatch stp = Stopwatch.StartNew();
for (int k = 0; k < t.Length; k++)
{
t[k] = Task.Run(() =>
{
for (int j = 0; j < runs; j++ )
{
i++;
}
});
}
Task.WaitAll(t);
stp.Stop();
Console.WriteLine("i = {0} should be = {1} ms={2}", i, runs * t.Length, stp.ElapsedMilliseconds);
Console.ReadLine();
}
Now a task could be pre-empted somewhere in the loop statements. But that wouldn't effect i. So the only way to see an effect on i would be, if a task is preempted when it just at the i++ statement. And thats what was to be shown: It CAN happen and it's more likely to happen when you have fewer but longer running tasks.
If you write Interlocked.Increment(ref i); instead of i++ the code runs much longer (because of the locking), but i is exactly what it should be!
I have a problem when multiple threads try to increase int. Here's my code:
private int _StoreIndex;
private readonly List<Store> _Stores = new List<Store>();
public void TestThreads()
{
_StoreIndex = 0;
for (int i = 0; i < 20; i++)
{
Thread thread = new Thread(() =>
{
while (_StoreIndex < _Stores.Count - 1)
{
_Stores[Interlocked.Increment(ref _StoreIndex)].CollectData();
}
});
thread.Start();
}
}
I would expect that int gets increased by one each time the thread executes this code. However, it does not. I have also tried using lock (new object()), but this doesn't work as well. The problem is that not all the stores collect data because (when debugging), _StoreIndex goes like 0, 1, 1, 3, 4, 5, for example. The second object in the list is obviously skipped.
What am I doing wrong? Thanks in advance.
In your case I would use the TPL to avoid all of these problems with manual thread creation and indexes in the first place:
Parallel.ForEach(_Stores, (store) => store.CollectData());
I think it should be corrected to:
Thread thread = new Thread(() =>
{
int index = 0;
while ((index = Interlocked.Increment(ref _StoreIndex)) < _Stores.Count - 1)
{
_Stores[index].CollectData();
}
});
Now index is local, so there is no interference, while _StoreIndex is only used atomically in a single place.
This is not an atomic operation:
_Stores[Interlocked.Increment(ref _StoreIndex)].CollectData();
Increment is atomic, but this line contains more code than a simple increment. You may need to sort out your indeces first, then use thread safe collection to hold your stores, like ConcurrentBag and perhaps consider TPL library and classes like Task and Parallel to perform the workload.