Search code examples
c#multithreading.net-4.5backgroundworkerstack-size

What is the stack size of a BackgroundWorker DoWork Thread? Is there way to change it?


I know for a C# main program the stack size 1 MB (32-bit and any) or 4 MB (64-bit), see Why is stack size in C# exactly 1 MB?

What is the default stack size of the BackgroundWorker DoWork thread?

Is there a way to change the stack size of the BackgroundWorker DoWork thread beside creating another thread like the following example:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{   
    Thread thread = new Thread(delegate()
    {
        // do work with larger stack size
    }, 8192 * 1024);
    thread.Start();
    thread.Join();
}

I'm using a BackgroundWorker because I've a Windows Forms application where I do some calculations inside the DoWork event. I'm doing it this way because I want to report back to the status line of the GUI and I want the possibility that user can cancel the calculations.

I'm getting a stack overflow error because I'm calling Intel MKLs LAPACKE_dtrtri which is heavily recursive, see http://www.netlib.org/lapack/explore-html/df/d5c/lapacke__dtrtri_8c_source.html.

The following code shows how I call Intel MKL:

public static double[,] InvTriangularMatrix(double[,] a, bool isupper)
{
    int n1 = a.GetLength(0);
    int n2 = a.GetLength(1);
    if (n1 != n2) throw new System.Exception("Matrix must be square");
    double[,] b = Copy(a);
    int matrix_layout = 101; // row-major arrays
    char uplo = isupper ? 'U' : 'L';
    char diag = 'N';
    int lda = Math.Max(1, n1);
    int info = _mkl.LAPACKE_dtrtri(matrix_layout, uplo, diag, n1, b, lda);
    if (info > 0) throw new System.Exception("The " + info + "-th diagonal element of A is zero, A is singular, and the inversion could not be completed");
    if (info < 0) throw new System.Exception("Parameter " + (-info) + " had an illegal value");
    return b;
}

and

[DllImport(DLLName, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)]
internal static extern int LAPACKE_dtrtri(
    int matrix_layout, char uplo, char diag, lapack_int n, [In, Out] double[,] a, int lda);

The InvTriangularMatrix is called inside my DoWork event. When I'm not setting the stack size I'm getting a stack overflow error inside the LAPACKE_dtrtri function.

The size of matrix can be in the order of 1000 x 1000 up to 100000 x 100000. If the matrix is larger than 65535 x 65535 see 2d-Array with more than 65535^2 elements --> Array dimensions exceeded supported range.


Solution

  • The stack size inside a BackgroundWorker DoWork event is the same as for the main thread.

    Prof:

    Set the stack size in a post build event to 8 MB for example:

    "$(DevEnvDir)..\..\VC\bin\editbin.exe" /STACK:8388608 "$(TargetPath)"
    

    Then ask for the stack size using the following code:

    [DllImport("kernel32.dll")]
    internal static extern void GetCurrentThreadStackLimits(out uint lowLimit, out uint highLimit);
    
    
    public static uint GetStackSize()
    {
        uint low, high;
        GetCurrentThreadStackLimits(out low, out high);
        return high - low;
    }
    

    Using GetStackSize in the main program and in the DoWork event return in both cases 8 MB or whatever you specified using EDITBIN /STACK.