Creating an Array of Threads in C# - c#

I have a very strange problem with my code. It will fully run the 1st for loop, then complete the foreach, but then it will skip back to the "ThreadStart IMAPDelegate" (line 1 of the for loop) and then crash because of an ArgumentOutOfRangeException. Can someone explain why the program is doing this? I debugged it line by line and it literally just skips back up into the a line in the for loop. If it had normally run the for loop again, it would have set x back to 0 and it would not have crashed. Any suggestions?
for (int x = 0; x < UserInfo.Count; x++)
{
ThreadStart IMAPDelegate = delegate{SendParams(UserInfo[x], IMAPServers[x]); };
MyThreads.Add(new Thread(IMAPDelegate));
}
foreach (Thread thread in MyThreads)
{
thread.Start();
}

This is by design when you use an anonymous method like that. As soon as the thread starts running, it executes the SendParams() method call. Which then bombs because the "x" variable is already incremented beyond UserInfo.Count. Fix:
for (int x = 0; x < UserInfo.Count; x++)
{
int user = x;
ThreadStart IMAPDelegate = delegate{SendParams(UserInfo[user], IMAPServers[user]); };
MyThreads.Add(new Thread(IMAPDelegate));
}

Related

Task.Factory.StartNew() generating object not initialzed error

I have this simple function,working as a task, that only print the values of a dataset. I pass the dataset from main function, and the index. The problem is that i have populated only 2 dataset index, however the function always jumps one ahead, i.e. in the last iteration it would want to start reading index 2, which is uninitialized and therefore the exception.
for (int i = 0; i < 2; i++)
{
tasks.Add(Task.Factory.StartNew(() => {
int a = i;
showNodeID(dataSet,a);
}));
}
and the function is
private static void showNodeID(DataSet[] ds, int a)
{
Console.WriteLine(a.ToString());
Console.WriteLine(ds[a].GetXml());
} //END
In the last iteration when i print 1 however in function if i print a it would be 2.
I assume you are aware of the dangers of captured counter variables in lambda closures, since you attempt to avoid the issue by assigning the counter to a locally-scoped variable. However, your assignment is happening too late – by the time the task starts and copies the value, the counter might already have been incremented by the next iteration. To properly avoid the issue, you need to copy the value before the task, not within it:
for (int i = 0; i < 2; i++)
{
int a = i;
tasks.Add(Task.Factory.StartNew(() =>
{
showNodeID(dataSet, a);
}));
}
If you just need to perform a parallel loop, you could alternatively use:
Parallel.For(0, 2, i => showNodeID(dataSet, i));

ArgumentOutOfRangeException. But it should not be there

So I have and method like this.
var someColletion = _someService.GetSomeCollection(someParam);
var taskCollection = new Task<double>[someCollection.Count];
for (int i = 0; i < taskCollection.Length; i++)
{
// do some stuff on the i-th element of someCollection and taskCollection
// and start the i-th task
}
Task.WaitAll(taskCollection);
double total = 0;
for (int i = 0; i < taskCollection.Length; i++)
{
// get the result of each task and sum it in total variable
}
return total;
the case is when it comes into first for loop and the number of elements in both collections are suppose 1 the ArgumentOutOfRangeException is being thrown and then AggregateException is being thrown on Task.WaitAll() because the i becomes 1 (I don't know why but it does) and when it tries to access the i-th (second) element in array that contains just one element, this happens. But there is more to this. If i set a break point before first loop and go step by step then this thing does not happen. when i becomes one the cycle ends. and everything's okay. now the method I provided above is called by an ASP.NET MVC Controller's Action which itself is called Asynchronously (by ajax call) suppose 3 times. and out of this three just one executes correctly other two do the thing I said above (if not breakpointed). I think that this problem is caused by ajax call most probably because when I breakpoint it stops other calls from executing. Can anyone suggest anything ?
I suspect you're using i within the first loop, capturing it with a lambda expression or anonymous method, like this:
for (int i = 0; i < taskCollection.Length; i++)
{
taskCollection[i] = Task.Run(() => Console.WriteLine(i));
}
If that's the case, it's the variable i which is being captured - not the value of the variable for that iteration of the loop. So by the time the task actually executes, it's likely that the value of i has changed. The solution is to take a copy of the iteration variable within the loop, in a separate "new" variable, and capture that in the anonymous function instead:
for (int i = 0; i < taskCollection.Length; i++)
{
int copy = i;
taskCollection[i] = Task.Run(() => Console.WriteLine(copy));
}
That way, each task captures a separate variable, whose value never changes.

Captured variables in ParameterizedThreadStart

I have the following code that creates 10 threads which in turn write out messages to the console:
for (int i = 0; i < 10; i++)
{
{
Thread thread = new Thread((threadNumber) =>
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j));
}
});
thread.Start(i);
}
}
My understanding is that ParameterizedThreadStart takes an object for which a copy of the reference is sent to the thread. If that is the case since I have not made a local copy of i within each loop all new threads would point to the same memory location meaning certain thread numbers could be 'missed out'. Having run this though (and even against a larger number of threads/sleep times) each value of i has its own thread. Can anyone explain why?
You haven't applied anything deferred or "captured" in the sense of creating an anonymous function that would wrap i.
The lambda function here does not reference i anywhere and its state is completely internalized/contained so no issues here:
(threadNumber) =>
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j));
}
});
The Start call here:
thread.Start(i);
Passes i by value (i.e. copies its value) because it is a "value type" and it's not captured in any kind of anonymous function. In this sense, it is passed as any normal struct would to any normal method (because this is exactly what is happening).
If instead you had written your lambda as this using i instead of your threadNumber:
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", i, j));
}
});
Then you would be in trouble. In this case i is referring to the original variable location and will be evaluated whenever the thread executes. This means it could be the current value of i when it was created (unlikely just due to processing times), or the value set later on in the for loop, or the last possible value 10, and quite possibly have the number skip or shared between iterations.

.NET 4.5 parallel processing and for loop

I am trying to create a list of tasks which depend on the number of processors available. I have a for loop which which seems to be behaving strangely. I am aware of the concept of closures in javascript, and it seems like something similar could be happening here:
var tasks = new Task[Environment.ProcessorCount];
for(int x = 0; x < Environment.ProcessorCount; x ++)
{
tasks[x] = Task.Run(() => new Segment(SizeOfSegment, x * SizeOfSegment, listOfNumbers).generateNewList());
}
What I am finding is when I break on the line in the for loop, the variable x seems to be correct, so it starts at 0 and ends at 3 (number of processors is 4). But when I put the break point within the constructor for Segment, I am finding that x was actually 4 when stepping back in the Call Stack.
Any help would be greatly appreciated.
You're capturing x within your lambda expression - but you've got a single x variable which changes values across the course of the loop, so by the time your task actually runs, it may well have a different value. You need to create a copy of the variable inside the loop, creating a new "variable instance" on each iteration. Then you can capture that variable safely:
for(int x = 0; x < Environment.ProcessorCount; x ++)
{
int copy = x;
tasks[x] = Task.Run(() => new Segment(SizeOfSegment,
copy * SizeOfSegment,
listOfNumbers).generateNewList());
}
(I'd also advise you to rename generateNewList to GenerateNewList to comply with .NET naming conventions.)

How to cause args to enter an endless loop?

I have a console application that uses a number of command line switches to control various methods. Each of the command line switches is handled by a switch statement that is within a for loop that iterates over each of the args.
for (int x = 0; x < args.Length; x++)
{
switch (args[x])
{
...
}
}
This works perfectly for my needs, however I need to add a --loop switch that causes the preceding args to be looped indefinitely based upon a timeout period specified by the --set-timeout switch.
The code I have so far is:
switch (args[x])
{
case "--set-timeout-5m":
timeout = 300000;
System.Threading.Thread.Sleep(timeout);
break;
....
case "--loop":
x = 0;
break;
}
The problem is setting x does not cause the for loop to continue from the start of args. It just sits there.
I am expecting x to have scope as the code is within the for loop and no errors are generated in Visual Studio. I am also expecting the break statement to break the case and pass x to the for loop.
Can anyone explain why it does not work or perhaps post a workaround?
for (int x = 0; x < 10; x++)
{
Console.Write(x);
x = 0;
}
prints
0 1 1 1 1 1 1 1 1 ...
because x++ is executed after each iteration.
If you want it to print
0 0 0 0 0 0 0 0 0 ...
you need to change it to
for (int x = 0; x < 10; x++)
{
Console.Write(x);
x = -1;
}
Your Thread.Sleep will just block the current thread. To set a timeout, get the current date before the loop:
DateTime start = DateTime.Now;
Then, on each iteration, check if the current time has exceeded the timeout, and if it has, break out of the loop:
if(DateTime.Now.Subtract(start).TotalMilliseconds >= timeout) {
// Stop your processin'!
}

Categories