Каков размер стека потока BackgroundWorker DoWork?Есть ли способ изменить это? - PullRequest
2 голосов
/ 05 июня 2019

Я знаю, что для основной программы на C # размер стека 1 МБ (32-разрядный и любой) или 4 МБ (64-разрядный), см. Почему размер стека в C # равен 1 МБ?

Каков размер стека по умолчанию для потока BackgroundWorker DoWork?

Есть ли способ изменить размер стека потока BackgroundWorker DoWork, кроме создания другого потока, как в следующем примере:

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();
}

Я использую BackgroundWorker, потому что у меня есть приложение Windows Forms, где я делаю некоторые вычисления внутри события DoWork. Я делаю это таким образом, потому что я хочу сообщить обратно в строку состояния графического интерфейса и хочу, чтобы пользователь мог отменить вычисления.

Я получаю ошибку переполнения стека, потому что я вызываю Intel MKL LAPACKE_dtrtri , который сильно рекурсивен, см. http://www.netlib.org/lapack/explore-html/df/d5c/lapacke__dtrtri_8c_source.html.

Следующий код показывает, как я называю 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;
}

и

[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);

InvTriangularMatrix вызывается внутри моего DoWork события. Когда я не устанавливаю размер стека, я получаю ошибку переполнения стека внутри функции LAPACKE_dtrtri.

Размер матрицы может быть от 1000 x 1000 до 100000 x 100000. Если матрица больше 65535 x 65535, см. 2d-массив с более чем 65535 ^ 2 элементами -> размеры массива превышен поддерживаемый диапазон .

1 Ответ

0 голосов
/ 06 июня 2019

Размер стека внутри события BackgroundWorker DoWork такой же, как и для основного потока.

Prof:

Установите размер стека в событии после сборки на 8 МБ, например:

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

Затем запросите размер стека, используя следующий код:

[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;
}

Использование GetStackSize в основной программе и в событии DoWork возвращает в обоих случаях 8 МБ или все, что вы указали с помощью EDITBIN /STACK.

...