Q:

Going from Parallel.ForEach to Multithreading

So I converted a recursive function to iterative and then used Parallel.ForEach but when I was running it through VTune it was only really using 2 logical cores at for the majority of its run time.
I decided to attempt to use managed threads instead, and converted this code:
for (int N = 2; N <= length; N <<= 1)
{
    int maxThreads = 4;
    var workGroup = Enumerable.Range(0, maxThreads);

    Parallel.ForEach(workGroup, i =>
    {
        for (int j = ((i / maxThreads) * length); j < (((i + 1) / maxThreads) * length); j += N)
        {
            for (int k = 0; k < N / 2; k++)
            {
                int evenIndex = j + k;
                int oddIndex = j + k + (N / 2);

                var even = output[evenIndex];
                var odd = output[oddIndex];

                output[evenIndex] = even + odd * twiddles[k * (length / N)];
                output[oddIndex] = even + odd * twiddles[(k + (N / 2)) * (length / N)];
            }
        }
    });
}

Into this: 
for (int N = 2; N <= length; N <<= 1)
{
    int maxThreads = 4;

    Thread one = new Thread(() => calculateChunk(0, maxThreads, length, N, output));
    Thread two = new Thread(() => calculateChunk(1, maxThreads, length, N, output));
    Thread three = new Thread(() => calculateChunk(2, maxThreads, length, N, output));
    Thread four = new Thread(() => calculateChunk(3, maxThreads, length, N, output));

    one.Start();
    two.Start();
    three.Start();
    four.Start();
}

public void calculateChunk(int i, int maxThreads, int length, int N, Complex[] output)
{
    for (int j = ((i / maxThreads) * length); j < (((i + 1) / maxThreads) * length); j += N)
    {
        for (int k = 0; k < N / 2; k++)
        {
            int evenIndex = j + k;
            int oddIndex = j + k + (N / 2);
            var even = output[evenIndex];
            var odd = output[oddIndex];

            output[evenIndex] = even + odd * twiddles[k * (length / N)];
            output[oddIndex] = even + odd * twiddles[(k + (N / 2)) * (length / N)];
        }
    }
}

The issue is in the fourth thread on the last iteration of the N loop I get a index out of bounds exception for the output array where the index is attempting access the equivalent of the length.
I can not pinpoint the cause using debugging, but I believe it is to do with the threads, I ran the code without the threads and it worked as intended.
If any of the code needs changing let me know, I usually have a few people suggest edits. Thanks for your help, I have tried to sort it myself and am fairly certain the problem is occurring in my threading but I can not see how.
PS: The intended purpose is to parallelize this segment of code.

A:

The observed behaviour is almost certainly due to the use of a captured loop iteration variable N. I can reproduce your situation with a simple test:
ConcurrentBag<int> numbers = new ConcurrentBag<int>();

for (int i = 0; i < 10000; i++)
{
    Thread t = new Thread(() => numbers.Add(i));

    t.Start();
    //t.Join(); // Uncomment this to get expected behaviour.
}

// You'd not expect this assert to be true, but most of the time it will be.
Assert.True(numbers.Contains(10000));

Put simply, your for loop is racing to increment N before the value of N can be copied by the delegate that executes the calculateChunk call. As a result calculateChunk sees almost random values of N going up to (and including) length <<= 1 - that's what's causing your IndexOutOfRangeException.
The output values you'll get will be rubbish too as you can never rely on the value of N being correct.
If you want to safely rewrite the original code to utilize more cores, move Parallel.ForEach from the inner loop to the outer loop. If the number of outer loop iterations is high, the load balancer will be able to do its job properly (which it can't with your current workGroup count of 4 - that number of elements is simply too low).

