class Thread1_8
{
static int shared_total;
static int thread_count;
static readonly object locker = new object();
static void Main()
{
int[,] arr = new int[5, 5] { { 1,2,3,4,5}, {5,6,7,8,9}, {9,10,11,12,13}, {13,14,15,16,17}, { 17,18,19,20,21} };
for(int i = 0; i < 5; i++)
{
new Thread(() => CalcArray(i, arr)).Start();
}
while(thread_count < 5)
{
}
Console.WriteLine(shared_total);
}
static void CalcArray(int row, int[,] arr)
{
int length = arr.GetLength(0);
int total = 0;
for(int j = 0; j < length; j++)
{
total += arr[row,j];
}
lock (locker)
{
shared_total += total;
thread_count++;
}
}
}
I keep getting a System.IndexOutOfRangeException.
The reason is because for some reason my "i" in the initial for loop is being set to 5 and STILL entering the loop for some reason. I don't understand why. At first I thought it might be because the each thread I create is incrementing the Array but it shouldn't since a Thread has a complete separate execution path, it should jump straight to the CalcArray method.
The reason why this happens is subtle: when you do this
for(int i = 0; i < 5; i++) {
new Thread(() => CalcArray(i, arr)).Start();
}
variable i goes through values 0 all the way to 5, at which point the loop stops, because 5 < 5 evaluates to false.
The thread starts after the loop is over, so the value of row that it sees is 5, not 0 through 4.
This can be fixed by making a local variable row inside the loop.
Another problem in your code is checking thread_count inside Main without locking, in a busy loop. This is not the best process of synchronizing with your threads. Consider using ManualResetEventSlim instead.
Related
I have to multiply matrix by vector using class Task from TPL (it's labaratory work and I have to). I did it using Parallel For and it works but now I'm stuck because I have no idea how to implement it using tasks.
public static int[] matxvecParallel(int [,] mat, int[] vec)ParallelFor
{
int[] res = new int[mat.GetLength(0)];
Parallel.For(0, mat.GetLength(0), i =>
{
for (int k = 0; k < mat.GetLength(1); k++)
{
res[i] += mat[i, k] * vec[k];
}
});
return res;
}
I did something stupid to find out how tasks works and I still don't understand.
How to change my code?
public static int[] matxvecTask(int[,] mat, int[] vec)
{
int[] res = new int[mat.GetLength(0)];
int countTasks = 4;
Task[] arrayOfTasks = new Task[countTasks];
for (int k = 0; k < mat.GetLength(0); k++)
{
for(int i = 0; i < countTasks; i++)
{
int index = i;
arrayOfTasks[index] = Task.Run(() =>
{
for (int j = 0; j < mat.GetLength(1); j++)
{
res[i] += mat[i, j] * vec[j];
}
});
}
}
return res;
}
To make it work, change this line to use index instead of i:
res[index] += mat[index, j] * vec[j];
When you use i, you fall in the trap of closures.
Then, you should also wait for all the tasks to complete before moving on to the next iteration:
Task.WaitAll(arrayOfTasks);
Now, you will gain absolutely nothing if you replace Parallel.For with tasks. You only make your code more complicated. Both tasks and Parallel will execute your computations on the thread pool. However, Parallel is optimized especially for the purpose and it easier to write and read.
As far as I know, the variable in thread should be not safe if not locked. But I tried it on Unity, and found it different.
I try the code below:
void Awake () {
Thread thread = new Thread(new ThreadStart (demo));
thread.Start ();
for (int i = 0; i < 5000; i++) {
count = count + 1;
}
}
void demo() {
for (int i = 0; i < 5000; i++) {
count = count + 1;
}
}
And I try to Debug.Log(count), and every times I try it that is 10000. But it should be a number which is less than 10000 because of not thread safety, shouldn't it? So can anyone tell me why?
Here's an Minimal, Complete, and Verifiable example of your code:
void Main()
{
Awake();
Console.WriteLine(count);
}
private int count = 0;
public void Awake()
{
Thread thread = new Thread(new ThreadStart(demo));
thread.Start();
for (int i = 0; i < 5000; i++)
{
count = count + 1;
}
thread.Join();
}
public void demo()
{
for (int i = 0; i < 5000; i++)
{
count = count + 1;
}
}
If you run that you get 10000 out. This is because by the time the thread has started the .Awake() method has finished its loop and thus no conflict occurs.
Try changing the loops to for (int i = 0; i < 50000; i++) then the result I got for one run is 89922. It changes each time, but sometimes I still get 100000.
The thread need some time to schedule to start. The main thread might finish the increments before the other thread start. Try to use a large value like 50000000.
Instead of printing o and -, I want to print the number of o and - on the console. However, I have no idea how to get how many times a loop spins in a thread before it gets switched to other threads.
If there are events something likes OnLeaving and OnEntering on a thread, I can get the number of spins in the given time slice. Unfortunately, I have no such events.
class Program
{
public const int N = 1000;
static void Main(string[] args)
{
ThreadStart ts = DoWork;
Thread t = new Thread(ts);
t.Start();
for (int x = 0; x < N; x++)
{
Console.Write('o');
}
t.Join();
}
private static void DoWork()
{
for (int x = 0; x < N; x++)
{
Console.Write('-');
}
}
}
Could you show me how to do this scenario?
To reiterate: AbhayDixit's comment gives you a cycle counter. You just need to add a locking mechanism and reset the counters after a context switch.
I have modified your code to include a cycle counter. Note that I have increased N significantly. Otherwise, one thread will just run through its 1000 iterations at once - because you no longer have a Write() instruction to slow it down.
class Program
{
public const int N = 1000000;
private static object _l = new object();
private static int _i = 0;
private static int _j = 0;
static void Main(string[] args)
{
ThreadStart ts = DoWork;
Thread t = new Thread(ts);
t.Start();
for (int x = 0; x < N; x++)
{
lock (_l)
{
// j-thread has run?
if (_j > 0)
{
// print and reset j
Console.Write("j{0} ", _j);
_j = 0;
}
_i++;
}
}
t.Join();
// print remaining cycles
// one of the threads will have run after the other has finished and
// hence not been printed and reset.
if (_i > 0)
Console.Write("i{0} ", _i);
if (_j > 0)
Console.Write("j{0} ", _j);
Console.ReadKey();
}
private static void DoWork()
{
for (int x = 0; x < N; x++)
{
lock (_l)
{
// i-thread has run?
if (_i > 0)
{
// print and reset i
Console.Write("i{0} ", _i);
_i = 0;
}
_j++;
}
}
}
}
I'm new to threads so it might be an easy one for you, but I've spent some hours trying to figure it out.
Let's say I have a function
public double Gain(List<int> lRelevantObsIndex, ushort uRelevantAttribute)
which needs some time to finish, but is a read only func.
I have an array of ushort[] values, and I want to get the ushort value that achieves the minimum value of the Gain function.
Here is what I've got so far, but it's not working:
lRelevantObsIndex is a read only index.
lRelevantAttributes is the list of ushort values.
//Initialize the threads
double[] aGains = new double[lRelevantAttributes.Count];
Thread[] aThreads = new Thread[lRelevantAttributes.Count];
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
aThreads[i].Start();
}
//Join the threads
for (int i = 0; i < lRelevantAttributes.Count; i++)
aThreads[i].Join();
//The easy part - find the minimum once all threads are done
ushort uResult = 0;
double dMinGain = UInt16.MaxValue;
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
if (aGains[i] < dMinGain)
{
dMinGain = aGains[i];
uResult = lRelevantAttributes[i];
}
}
return uResult;
I know this is a simple multithreading question - but still need your brains since I'm new to this.
This one is somewhat tricky: your for loop uses a modified value here (a so-called access to modified closure)
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
aThreads[i].Start();
}
At the time the thread starts, i will be different in your lambda, accessing a wrong item. Modify your loop as follows:
for (int ii = 0; ii < lRelevantAttributes.Count; ii++)
{
var i = ii; // Now i is a temporary inside the loop, so its value will be captured instead
aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
aThreads[i].Start();
}
This will fix the problem, because lambdas will capture the current value of the temporary variable i on each iteration of the loop.
I'm not sure if this is your problem, but it is a problem:
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
aThreads[i].Start();
}
When a lambda refers to a loop variable, the binding is delayed, so that when your lambda actually runs, it takes the value of i at the time the lambda runs, not the value it had when the lambda was created. To fix this, declare a secondary variable inside the loop, and use that in the lambda:
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
int j = i;
aThreads[i] = new Thread(() => aGains[j] = Gain(lRelevantObsIndex, lRelevantAttributes[j]));
aThreads[i].Start();
}
You can do the same on Task
[Fact]
public void Test()
{
List<Task<int>> tasks = Enumerable.Range(0, 5) //- it's equivalent how many threads
.Select(x => Task.Run(() => DoWork(x)))
.ToList();
int[] result = Task.WhenAll(tasks).Result; //- Join threads
result.ToList().ForEach(Console.WriteLine);
}
private int DoWork(int taskId)
{
return taskId;
}
Result output:
3
0
1
2
4
This question already has answers here:
Captured variable in a loop in C#
(10 answers)
Closed 9 years ago.
I'm fairly new to C# threading, so apologies in advance for this newbie error. The aim of the following code is to evaluate the fitness of a population that is stored in an array called members. The procedure members.calculateFitness() is a black box (i.e. I can't modify it to improve performance), so I'm trying to setup threads that call the black box simultaneously, and each thread will deal with 1/THREAD_COUNT population members (so if THREAD_COUNT=4, each thread will deal with 1/4 of the population).
In the first for loop I initialise each thread. In the second for loop, I start the thread.
public void ThreadedPrintPopFitness ()
{
int THREAD_COUNT = 1;
int membersPerThread = members.Length / THREAD_COUNT;
Thread[] fitnessCalculator = new Thread[THREAD_COUNT];
int[] threadResult = new int[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
int start = i * membersPerThread;
int stop = (i+1) * membersPerThread;
fitnessCalculator [i] = new Thread (() => getMaxFitness (members, start, stop, ref threadResult [i]));
}
for (int i = 0; i < THREAD_COUNT; i++) {
fitnessCalculator [i].Start ();
}
for (int i = 0; i < THREAD_COUNT; i++) {
fitnessCalculator [i].Join ();
}
int maxFitness = 0;
for (int i = 0; i < THREAD_COUNT; i++) {
if (maxFitness < threadResult [i])
maxFitness = threadResult [i];
}
Console.WriteLine ("(ThreadedCount) Fittest Population Member's Fitness: " + maxFitness);
}
private static void getMaxFitness (PopulationMember[] members, int start, int stop, ref int result)
{
int maxFitness = 0;
for (int i = start; i < stop && i < members.Length; i++) {
if (members [i].calculateFitness () > maxFitness) {
maxFitness = members [i].lastFitness;
}
}
result = maxFitness;
}
Stepping through the code shows that it gets into the second for loop, and then jumps back to the first for loop and declares an IndexOutOfBoundsException on the integer i. I can see that i = THREAD_COUNT (I've tried with different numbers for THREAD_COUNT).
I'm completely baffled, what am I doing wrong?
Thanks in advance!
Servy has it spot on, I even remember reading about this in John Skeet's book now. I had to make a copy of i within the for loop, this fixed it.
Thanks!
As written in the comments, i is captured, and when increased, the function refers to the new value.
What you should do is copy its value to a local variable:
for (int i = 0; i < THREAD_COUNT; i++) {
int start = i * membersPerThread;
int stop = (i+1) * membersPerThread;
int resultId = i;
fitnessCalculator [i] = new Thread (() => getMaxFitness (members, start, stop, ref threadResult [resultId]));
}