首页 > 解决方案 > 有没有办法增加c#中的堆栈大小?

问题描述

在几年没有做任何事情之后,我又回到了编程领域,并创建了一个数独游戏来让我的脚再次湿透。我编写了一个递归函数来蛮力解决方案,它会为简单的板状态执行此操作,但对于更复杂的板状态,大多数时间都会遇到堆栈溢出。我知道可以使用循环或更有效的算法来避免这种情况,但由于这是为了学习,我想知道如何为堆栈分配更多内存(承认这不是解决问题的最佳方法)。

这里有一个答案:如何更改 .NET 程序的堆栈大小?建议使用分配更多内存的线程不起作用,因为据我所知,.NET 4.0 不会让您将线程的最大分配内存增加到默认值之外。

另一种解决方案建议使用 EDITBIN.EXE,但我是 Visual Studio 的新手,还没有找到我理解的解释。

同样,我发现您可以使用 .def 文件来指示更大的默认堆栈大小,但没有找到我理解的关于如何创建/实现一个的解释。

任何人都可以提供 EDITBIN.EXE 或 .def 文件实现的新手级解释,或者提供另一种增加堆栈大小的方法吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Sudoku
{
    //object keeps track of the value of all numbers currently on the board using an array

    class BoardState
    {
        int testcount = 1;
        //3d array of ints representing all values on the board, represted as region, column, row
        int[,,] boardVals;

        //3d array of bools representing if a number is immutable (true cannot be changed, false can be)
        bool[,,] fixedVals;

        //create a blank board if no initial values are provided
        public BoardState()
        {
            boardVals = new int[9, 3, 3];
            fixedVals = new bool[9, 3, 3];
        }

        //create a board with the listed initial values as immutable
        public BoardState(int[,,] inputVals)
        {
            boardVals = inputVals;
            fixedVals = new bool[9,3,3];
            for (int i = 0; i < 9; ++i)
                for (int j = 0; j < 3; ++j)
                    for (int k = 0; k < 3; ++k)
                        if (boardVals[i, j, k] > 0) fixedVals[i, j, k] = true;
        }

        //update the state of the board using the coordinates of a single value
        //**note** method has not been implemented and tested yet
        public void updateState(int region, int column, int row, int val)
        {
            if (!fixedVals[region, column, row])
            {
                boardVals[region, column, row] = val;
            }
        }

        //update the state of the board to match the state of another board
        public void updateState(int[,,] newState)
        {
            boardVals = newState;
        }

        public int[,,] getVals()
        {
            return boardVals;
        }

        public bool[,,] getFixed()
        {
            return fixedVals;
        }

        //set all non-zero values to be immutable
        public void setFixed()
        {
            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 3; j++)
                    for (int k = 0; k < 3; k++) {
                        if (boardVals[i, j, k] != 0)
                            fixedVals[i, j, k] = true;
                        else
                            fixedVals[i, j, k] = false;
                    }
        }

        //test method
        public void testState()
        {
            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 3; j++)
                    for (int k = 0; k < 3; k++)
                        Console.WriteLine(boardVals[i, k, j]);
        }

        //accepts a 3d array representing the current board state.
        //returns a 3d bool array denoting whether any region, row, or column is invalid (true=invalid)
        //first value of array designates the region, row, or column respectively
        //second value designates which of those is invalid
        public bool[,] validateBoard()
        {
            bool[,] valid = new bool[3, 9];
            int[,] rows = makeRows(boardVals);
            int[,] cols = makeCols(boardVals);

            //compare each value in each row to each other value in that row
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {

                    //only validate an entry if it has been assigned a value
                    if (rows[i, j] != 0)
                    {
                        for (int k = 0; k < 9; k++)
                        {
                            //if two values are not the same entry and are equal, set that entry to invalid
                            if (j != k && rows[i, j] == rows[i, k])
                                valid[1, i] = true;
                        }
                    }
                }
            }

            //compare each value in each column to each other value in that column
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {

                    //only validate an entry if it has been assigned a value
                    if (cols[i, j] != 0)
                    {
                        for (int k = 0; k < 9; k++)
                        {
                            //if two values are not the same entry and are equal, set that entry to invalid
                            if (j != k && cols[i, j] == cols[i, k])
                                valid[2, i] = true;
                        }
                    }
                }
            }

            //compare each value in each region to each other value in that region
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        //only validate an entry if it has been assigned a value
                        if (boardVals[i, j, k] != 0)
                        {
                            for (int l = 0; l < 3; l++)
                            {
                                for (int m = 0; m < 3; m++)
                                {
                                    //if two values are not the same entry and are equal, set that entry to invalid
                                    if (!(l == j && m == k) && boardVals[i, j, k] == boardVals[i, l, m])
                                        valid[0, i] = true;
                                }
                            }
                        }
                    }
                }
            }

            return valid;
        }

        public bool isValid()
        {
            bool retFlag = true;
            bool[,] valid = new bool[3, 9];
            int[,] rows = makeRows(boardVals);
            int[,] cols = makeCols(boardVals);

            //for (int i = 0; i < 9; i++)
            //    for (int j = 0; j < 3; j++)
            //        for (int k = 0; k < 3; k++)
            //            Console.Write(boardVals[i, j, k]);

            //compare each value in each row to each other value in that row
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {

                    //only validate an entry if it has been assigned a value
                    if (rows[i, j] != 0)
                    {
                        for (int k = 0; k < 9; k++)
                        {
                            //if two values are not the same entry and are equal, set that entry to invalid
                            if (j != k && rows[i, j] == rows[i, k])
                            {
                                retFlag = false;
                            }

                        }
                    }
                }
            }

            //compare each value in each column to each other value in that column
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {

                    //only validate an entry if it has been assigned a value
                    if (cols[i, j] != 0)
                    {
                        for (int k = 0; k < 9; k++)
                        {
                            //if two values are not the same entry and are equal, set that entry to invalid
                            if (j != k && cols[i, j] == cols[i, k])
                            {
                                retFlag = false;
                            }
                        }
                    }
                }
            }

            //compare each value in each region to each other value in that region
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        //only validate an entry if it has been assigned a value
                        if (boardVals[i, j, k] != 0)
                        {
                            for (int l = 0; l < 3; l++)
                            {
                                for (int m = 0; m < 3; m++)
                                {
                                    //if two values are not the same entry and are equal, set that entry to invalid
                                    if (!(l == j && m == k) && boardVals[i, j, k] == boardVals[i, l, m])
                                    {
                                        retFlag = false;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return retFlag;
        }

        //returns an array of all the values in each row
        public int[,] makeRows(int[,,] boardState)
        {
            int[,] rows = new int[9, 9];

            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 9; j++)
                    rows[i, j] = boardState[j / 3 + ((i / 3) * 3), j % 3, i - ((i / 3) * 3)];

            return rows;
        }

        //returns an array of all values in each column
        public int[,] makeCols(int[,,] boardState)
        {
            int[,] cols = new int[9, 9];

            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 9; j++)
                    cols[i, j] = boardState[((j / 3) * 3) + (i / 3), i - ((i / 3) * 3), j % 3];

            return cols;
        }

        //update the board state to a state read in from a file
        public void updateFromFile(Stream update)
        {
            int[,,] newVals = new int[9, 3, 3];
            int[,,] newFixed = new int[9, 3, 3];

            StreamReader file = new StreamReader(update);

            for (int i = 0; i < 9; i++){
                for (int j = 0; j < 3; j++){
                    for (int k = 0; k < 3; k++){
                        boardVals[i, j, k] = (int)char.GetNumericValue((char)file.Read());
                    }
                }
            }

            for (int i = 0; i < 9; i++){
                for (int j = 0; j < 3; j++){
                    for (int k = 0; k < 3; k++){
                        fixedVals[i, j, k] = (0 != ((int)char.GetNumericValue((char)file.Read())));
                    }
                }
            }

            file.Close();
        }

        public void Solve(int entry, int val)
        {
            Console.WriteLine("This is call number " + ++testcount);

            //returns if all values are filled and valid
            if (entry == 81)
            {
                Console.WriteLine("Solved!");
                return;
            }

            //creating reference coordinates based on entry value
            int reg = entry / 9;
            int col = (entry - (reg * 9)) % 3;
            int row = (entry - (reg * 9)) / 3;


            //if current entry being checked is a fixed value, go the next value
            if (!fixedVals[reg, row, col])
            {
                Console.WriteLine("");
                Console.WriteLine("Making an attempt at entry " + entry + " using value " + val);
                Console.WriteLine("This entry is at region " + reg + ", col " + col + ", row " + row);

                //assign entry the value to be tested
                boardVals[reg, row, col] = val;

                //if the value is valid, go to the next entry
                if (isValid())
                {
                    Console.WriteLine("Entry Valid at " + entry);
                    val = 1;
                    entry++;
                    Console.WriteLine("Trying the next entry at " + entry);
                    Solve(entry, val);
                }

                //if the value is invlid and all 9 values have not been tried,
                //increment value and call again at same entry
                if (!isValid() && val < 9)
                {
                    Console.WriteLine("Entry Invalid at " + entry + " with value " + val);
                    ++val;
                    Console.WriteLine("Trying again with value " + val);
                    Solve(entry, val);
                }

                //if the value in invalid and all 9 values have been tried,
                //zero out the entry and go back to the previous non-fixed entry
                if (!isValid() && val == 9)
                {
                    do
                    {
                        boardVals[reg, row, col] = 0;

                        Console.WriteLine("Reached Value 9 and was still invalid");
                        --entry;
                        Console.WriteLine("Trying again at entry " + entry);
                        Console.WriteLine("The value at that entry is " + boardVals[reg, row, col]);
                        reg = entry / 9;
                        col = (entry - reg * 9) % 3;
                        row = (entry - reg * 9) / 3;
                        if (fixedVals[reg, row, col])
                            Console.WriteLine("But that's a fixed value, so I'll go back one more");
                        Console.WriteLine("");
                    } while (boardVals[reg, row, col] == 9 || fixedVals[reg, row, col]);
                    val = boardVals[reg, row, col] + 1;

                    Solve(entry, val);

                }
            }
            else Solve(++entry, val);
        }
    }
}

标签: c#multithreadingrecursionstack-overflow

解决方案


严重的警告

如果您在程序中使用递归并达到 StackOverflowException 是一个实际威胁的程度,请不要将增加堆栈大小作为有效的解决方案。

如果你遇到 StackOverflowException,你就做错了;您应该改为使用Stack<T>深度优先处理或Queue<T>广度优先处理。例子。


解决方案

这可以通过使用editbin.exe与此软件包一起安装的 来实现; VC++ 工具

找到 的位置editbin.exe,我的位置是C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\editbin.exe,我建议使用voidtools的 Everything 代替微软可怕的搜索来找到这个。

手动设置堆栈大小

导航到您的 bin 文件夹并执行以下命令:

"<full path of editbin.exe>" /stack:<stack size in bytes, decimal> <your executable name>

例如我执行了这个:

"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\EDITBIN.EXE" /stack:2097152 ExampleProgram.exe

它将堆栈保留大小设置为 2MB。

有了这个,我能够达到两倍的递归水平;(左侧为 1MB 堆栈预留,右侧为 2MB 堆栈预留)。

递归级别

自动设置堆栈大小

右键单击您的项目并选择“选项”,然后单击“构建事件”并将以下内容添加到您的构建后事件中:

"<full path of editbin.exe>" /stack:<stack size in bytes, decimal> "$(TargetPath)"

例如我添加了

"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\x64\EDITBIN.EXE" /stack:2097152 "$(TargetPath)"

这将在editbin.exe您每次构建可执行文件时运行。

注意:当您从 Visual Studio 运行程序时,您将看到低得多的递归级别,就像您通过资源管理器或 cmd 显式运行它一样。但是,如果从 1MB 堆栈保留移动到 2MB 堆栈保留,您仍然会看到递归级别增加 2 倍。


推荐阅读