【问题标题】:Why is Console.Readline not executing as expected为什么 Console.Readline 没有按预期执行
【发布时间】:2011-08-28 06:06:30
【问题描述】:

我可以使用以下代码。我在这里遇到的问题是代码通过 while 循环运行,而无需等待行 String temp = Console.ReadLine() 上的输入。请帮助理解为什么以及如何解决。提前致谢!

   /*Banker's algorithm Implementation*/
  class Program
  {

        static void Main(string[] args)
        {
              int n = 0;//number of resources we will  be dealing with
              int proc_num = 0;//Total number of processes to share available resources

              IDictionary<String, SysProcess> processes = new Dictionary<String, SysProcess>();
              IDictionary<String, int> MaxR = new Dictionary<String, int>();// maximum available resources
              IDictionary<String, int> avail = new Dictionary<String, int>();// Available resources after first allocation
              Dictionary<String, int> availsum = new Dictionary<string, int>();

              //Start  
              while (true)
              {
                    Console.WriteLine(" What is number of resources to be shared? : ");
                          if (!int.TryParse(Console.ReadLine(), out n))
                          {
                                Console.WriteLine(" Error Please provide valid number --- {0}!", n);
                          }
                          else
                          {
                                break;
                          }
              }

              //get the maximum number of each Resources Ie Total Resources Available
              while (true && n>0)
              {
                    Console.WriteLine("Using a comma delimited list(e.g. 0, 0, 0, 0) list maximum of each of the {0} resources : ", n);
                    String temp;
                      temp = Console.ReadLine();

                    if (!String.IsNullOrEmpty(temp))
                    {
                          String[] maxR = temp.Split(',');
                          for (int a = 1; a <= n; a++)
                          {
                                MaxR.Add("Resource#" + a.ToString(), Convert.ToInt32(maxR[a]));
                          }
                          break;
                    }
              }


              while (true && n>0)
              {
                    Console.Write("Enter total number of processes to share the available resources :");
                    if (!int.TryParse(Console.Read().ToString(), out proc_num))
                    {
                          Console.WriteLine(" Error Please provide valid number --- {0}!", proc_num);
                    }
                    else
                    { break; }
              }

              if(proc_num > 0)
              {
                    //Request Process Max and allocated resources data
                    for (int i = 1; i <= proc_num; i++)
                    {
                          Console.Write("Using a comma delimited list, Enter total number of Resources 1 through {0} are needed by PROCESS#{1} ?", n, i);
                          String[] temps = Console.ReadLine().Split(',');
                          SysProcess tempproc = new SysProcess("Process#" + i.ToString());

                          for (int a = 0; a < temps.Length; a++)
                          {
                                tempproc.Add_max_resource("Resource#" + (a + 1).ToString(), Convert.ToInt32(temps[a]));
                          }

                          //How many resources have already been allocated to each resource
                          temps = null;
                          Console.Write("Using a comma delimited list,Enter number of resources 1 through {0} already  allocated to PROCESS#{1} ? ", n, i);
                          temps = Console.ReadLine().Split(',');
                          for (int a = 0; a < temps.Length; a++)
                          {
                                tempproc.add_alloc_resource("Resource#" + (a + 1).ToString(), Convert.ToInt32(temps[a]));
                          }
                          processes.Add("Process#" + i.ToString(), tempproc);
                    }


                    Console.WriteLine("Processing . . . ");
                    Console.WriteLine();
                    Console.WriteLine("Available resources ");

                    //Compute Available Resources 
                    for (int i = 0; i < n; i++)
                    {
                          if (!availsum.ContainsKey("Resource#" + (i + 1).ToString()))
                                availsum.Add("Resource#" + (i + 1).ToString(), 0);
                          foreach (SysProcess sp in processes.Values)
                          {     //add sum up the available
                                availsum["Resource#" + (i + 1).ToString()] += sp.alloc_resources["Resource#" + (i + 1).ToString()];
                          }
                    }

                    //print out the availables we computed 

                    Console.Write(" avail< ");
                    for (int j = 0; j < n; j++)
                    {

                          Console.Write(availsum["Resource#" + (j + 1).ToString()] + ",");

                          if (j + 1 == n)//if this is the last one, go ahead and output the rest
                                Console.Write("{0} > ", availsum["Resource#" + (j + 1).ToString()]);
                    }


                    // Printing resources still needed 
                    Console.WriteLine();
                    foreach (SysProcess p in processes.Values)
                    {
                          p.print_needed();
                    }


                    //a) Find a row in the Need matrix which is less than the Available vector. 
                    //If such a row exists, then the process represented by that row may complete
                    //with those additional resources. If no such row exists, eventual deadlock is possible.
                    Dictionary<String, int> _currentavailsum;

                    foreach (SysProcess p in processes.Values)
                    {
                          int TotalSproccounter = 0;
                          String safelead;
                          if (isprocessSafe(n, p, availsum))
                          {
                                TotalSproccounter++;
                                safelead = p.id;
                                _currentavailsum = new Dictionary<String, int>();
                                _currentavailsum = availsum;//get a copy of the original data to begin with
                                foreach (SysProcess q in processes.Values)
                                {
                                      if (q != p)//we only want to compare with the others from here
                                      {
                                            if (isprocessSafe(n, p, _currentavailsum))
                                            {
                                                  update_availsum(n, q, ref  _currentavailsum);//update the currentavail count
                                                  TotalSproccounter++;
                                                  //update print 
                                                  safelead += ", " + q.id;
                                            }
                                      }
                                }

                                if (TotalSproccounter == proc_num)
                                {
                                      Console.WriteLine("Safe allocation < {0} >", safelead);
                                }
                                else
                                {
                                      Console.WriteLine("Deadlock reached/unsafe allocation :  < {0} >", safelead);
                                }
                          }
                    }
               }
              Console.ReadLine();
        }

        //compares the number of resources needed against the number of resources available
        public static Boolean isprocessSafe(int n, SysProcess p, IDictionary<String, int> avail)
        {
              int safecount = 0;
              foreach (String resourcekey in avail.Keys)
              {
                    if (p.need_resources.ContainsKey(resourcekey) && p.need_resources[resourcekey] <= avail[resourcekey])
                    {
                          safecount++;
                    }

              }
              if (safecount == n)
              {

                    return true;
              }
              return false;
        }

        //compares the number of resources needed against the number of resources available
        public static void update_availsum(int n, SysProcess p, ref Dictionary<String, int> _currentavailsum)
        {
              foreach (String resourcekey in _currentavailsum.Keys)
              {
                    if (p.need_resources.ContainsKey(resourcekey))
                    {
                          _currentavailsum[resourcekey] += p.need_resources[resourcekey];
                    }

              }
        }

  }

  //container class for processes 
  public class SysProcess
  {
        public String id { get; set; }
        Dictionary<String, int> _max_resources = null; // will hold the Resource name and the  the number of resources 
        Dictionary<String, int> _alloc_resources = null;//allocated resources
        Dictionary<String, int> _need_resources = null;//allocated resources

        public Dictionary<String, int> max_resources
        {
              get
              { return _max_resources; }

        }

        public Dictionary<String, int> alloc_resources
        {
              get
              {
                    return _alloc_resources;

              }
        }

        public Dictionary<String, int> need_resources
        {
              get
              {
                    return _need_resources;

              }
        }

        public SysProcess(String procID)
        {
              _max_resources = new Dictionary<String, int>();
              _alloc_resources = new Dictionary<String, int>();
              id = procID;
        }

        public void Add_max_resource(String resource, int count)
        {
              _max_resources.Add(resource, count);
        }

        public void add_alloc_resource(String resource, int count)
        {
              _alloc_resources.Add(resource, count);
              _need_resources.Add(resource, _max_resources[resource] - alloc_resources[resource]);
        }

        public void print_needed()
        {
              Console.Write(id);
              foreach (int s in _need_resources.Values)
              {
                    Console.Write(" {0}", s);
              }

        }
  }

在此处添加整个代码可能是个好主意,因为我仍然无法弄清楚这一点。请帮忙

【问题讨论】:

  • 您的循环条件是多余的:IsNullOrWhiteSpace() 将涵盖 IsNullOrEmpty() 涵盖的所有情况。非挑剔问题:您如何为应用程序提供输入?您是从另一个应用程序输入数据,还是将文件定向到该应用程序?
  • 什么是n?此代码应该可以正常工作并等待输入
  • 您确定项目输出类型是“控制台应用程序”吗?这项工作是否发生在主线程上?
  • 您是否将肘部放在输入键上?
  • 你在做线程吗?我不明白你为什么会这样,但我看不出有任何其他原因这不起作用。我假设您只是一遍又一遍地看到“使用逗号分隔列表(例如...)”?还是 readline 会自动返回一个终止循环的值?

标签: c# .net windows console-application


【解决方案1】:

问题是使用了有问题的方法Console.Read()。此方法将阻塞,直到输入一整行文本,但它只返回第一个字符,将剩余文本留在输入缓冲区中。执行Console.ReadLine() 操作时,用于输入第一个值和解除阻塞读取操作的回车符仍位于输入缓冲区中。因此,返回一个空行。

我建议您将Console.Read().ToString() 替换为Console.ReadLine() 以解决此问题。

这个问题可以用这段代码来演示:

    static void Main(string[] args)
    {
        string value = Console.Read().ToString();
        Console.WriteLine("You entered: {0}", value);
        Console.WriteLine("Press ENTER to continue...");
        Console.ReadLine();   // Returns immediately.
        Console.WriteLine("Continuing....");
    }

并像这样固定:

        string value = Console.ReadLine();

【讨论】:

  • 谢谢,原来是这个问题。一旦我切换到使用 Console.ReadLine(),问题就消失了。
【解决方案2】:

问题是您误解了Console.Read 的作用。它从输入流中读取下一个字符并将其作为整数返回。但是......这是好的部分,在你按下 Enter 之前什么都不会出现。因此,如果您在第一个提示符下输入“abc”并按 Enter,您将从缓冲区中获取第一个字符,作为整数 (97)。但是输入缓冲区将包含“bc”和换行符,然后将被Readline 使用。

如果您想要来自Console 的字符串,请调用ReadLine,而不是Read

【讨论】:

    【解决方案3】:

    问题可能是您尝试从控制台读取的输入流中已有的内容。如果您不想担心缓冲区中已有的内容,可以尝试刷新它,以便从新的空输入状态开始。顺便说一句,所有 Console.Read* 函数似乎都是阻塞函数。但是,还有一个 KeyAvailable 属性,它指示是否有可用的内容。

    这提供了以下代码:

    private void clearInputBuffer()
    {
       while(Console.KeyAvailable)
       {
           Console.Read(); // read next key, but discard
       }
    }
    

    或者,输入缓冲区在基本级别上是一个流。一个 TextReader,具体来说。这可以从

    获得
    Console.In
    

    因此,您可以使用那里的函数,例如 .ReadToEnd(),在进入 While(true) 循环之前清除缓冲区。

    【讨论】:

    • 我尝试了上面的解决方案,但它似乎没有改变任何东西。在运行期间单步执行代码时,我发现确实没有带回任何数据。
    【解决方案4】:

    您的项目是否配置为控制台应用程序?它需要使用不同的开关构建,以便在 exe 文件中设置标志,以便操作系统加载程序知道它需要为进程创建一个控制台窗口。 GUI 应用不会设置该标志,也不会获得控制台窗口。

    在 VS2010 中,右键单击项目的属性链接,单击应用程序选项卡,然后将输出类型从 Windows 应用程序更改为控制台应用程序。重建并运行。

    【讨论】:

    • 我没有想到的好点。我刚刚检查过,如果项目不是控制台项目,Console.ReadLine() 将立即返回。
    • 这是我一直对自己做的傻事。 :P
    • 刚刚检查,输出类型已经设置为控制台应用程序。
    【解决方案5】:

    您的输入中可能有重复/额外的换行符。这段代码看起来非常适合解析逗号分隔的文件...

    【讨论】:

    • 我刚刚发布了我所有的代码供您查看。我那里没有多余的行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    • 1970-01-01
    相关资源
    最近更新 更多