BackgroundWorker DoWork 线程的堆栈大小是多少?有没有办法改变它?

Posted

技术标签:

【中文标题】BackgroundWorker DoWork 线程的堆栈大小是多少?有没有办法改变它?【英文标题】:What is the stack size of a BackgroundWorker DoWork Thread? Is there way to change it? 【发布时间】:2019-10-20 19:05:57 【问题描述】:

我知道 C# 主程序的堆栈大小为 1 MB(32 位和任何)或 4 MB(64 位),请参阅Why is stack size in C# exactly 1 MB?

BackgroundWorkerDoWork 线程的默认堆栈大小是多少?

除了创建另一个线程之外,有没有办法改变 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 事件中进行一些计算。我这样做是因为我想向 GUI 的状态行报告,并且我希望用户可以取消计算。

我收到堆栈溢出错误,因为我正在调用英特尔 MKLs LAPACKE_dtrtri,这是高度递归的,请参阅 http://www.netlib.org/lapack/explore-html/df/d5c/lapacke__dtrtri_8c_source.html。

以下代码显示了我如何调用英特尔 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-Array with more than 65535^2 elements --> Array dimensions exceeded supported range。

【问题讨论】:

BGW 使用线程池线程,你不能改变它们的堆栈大小。请注意这种解决方法,通常只需要解决递归代码的问题。如果在测试时出现问题,那么当它需要处理真实数据集时,它在生产中很少会变得更好。 如果您发现自己不得不增加堆栈大小,那么您真正应该做的可能是将递归方法转换为使用Stack&lt;T&gt; 实现的迭代方法。 如果你在 DoWork 中创建线程,那么 BackgroundWorker 不是你想要的。 你为什么要在 BGW 的后台线程中启动 *another background * 线程?无论如何,BGW 已经过时,完全被Task.RunIProgress&lt;T&gt; 取代。 它是正式的未指定,因为它取决于 CLR 主机,如果您以 Windows 为目标,那么它是任何风格的兆字节。永远不足以让你开心。货比三家,矩阵求逆不是火箭科学。试试 Math.NET。 【参考方案1】:

BackgroundWorkerDoWork 事件中的堆栈大小与主线程相同。

教授:

例如将构建后事件中的堆栈大小设置为 8 MB:

"$(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;

在主程序和 DoWork 事件中使用 GetStackSize 在这两种情况下都会返回 8 MB 或您使用 EDITBIN /STACK 指定的任何值。

【讨论】:

这仅在您启动而不调试时才有效,否则为 1 MB。

以上是关于BackgroundWorker DoWork 线程的堆栈大小是多少?有没有办法改变它?的主要内容,如果未能解决你的问题,请参考以下文章

未调用 BackgroundWorker DoWork 函数

在WPF 中Dowork事件触发不了

BackgroundWorker DoWork 线程的堆栈大小是多少?有没有办法改变它?

BackgroundWorker 组件 -- 进度条

winform异步系统升级—BackgroundWorker

c# 关于backgroundWorker的取消