Почему Console.Readline не работает должным образом - PullRequest
3 голосов
/ 18 мая 2011

У меня есть следующий код для работы. Проблема, с которой я столкнулся, заключается в том, что код проходит через цикл 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);
              }

        }
  }

Вероятно, это хорошая идея добавить весь код здесь, так как я до сих пор не могу понять это. Пожалуйста, помогите

Ответы [ 5 ]

6 голосов
/ 19 мая 2011

Проблема заключается в использовании проблемного метода 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();
2 голосов
/ 18 мая 2011

Ваш проект настроен как консольное приложение?Он должен быть собран с разными переключателями, чтобы установить флаги в exe-файле, чтобы загрузчик ОС знал, что ему нужно создать консольное окно для процесса.Приложения с графическим интерфейсом не устанавливают этот флаг и не получают окно консоли.

В VS2010 щелкните правой кнопкой мыши ссылку "Свойства" вашего проекта, перейдите на вкладку "Приложение" и измените Тип вывода с приложения Windows на консольЗаявка.Перестройте и запустите.

0 голосов
/ 19 мая 2011

Проблема в том, что вы неправильно истолковываете то, что делает Console.Read.Он читает следующий символ из входного потока и возвращает его как целое число.Но ... и вот хорошая часть, ничего не приходит, пока вы не нажмете Enter.Поэтому, если вы введете «abc» в первом приглашении и нажмете Enter, вы получите первый символ из буфера в виде целого числа (97).Но входной буфер будет содержать «bc» и символ новой строки, который будет затем использоваться Readline.

Если вы хотите получить строку из Console, вызовите ReadLine, а не Read.

0 голосов
/ 18 мая 2011

Возможно, проблема в содержимом входного потока, который вы пытаетесь прочитать с консоли. Если вы не хотите беспокоиться о том, что уже находится в буфере, вы можете попытаться очистить его, чтобы начать со свежего, пустого состояния ввода. Неожиданно все функции Console.Read * оказываются блокирующими функциями. Однако есть также свойство KeyAvailable, которое указывает, доступно ли содержимое.

Это обеспечивает следующий код:

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

Альтернативно, буфер для ввода на базовом уровне является потоком. TextReader, чтобы быть конкретным. И это доступно от

Console.In

Таким образом, вы можете использовать функции, такие как .ReadToEnd (), чтобы очистить буфер прямо перед тем, как войти в цикл While (true).

0 голосов
/ 18 мая 2011

Возможно, у вас есть дубликаты / дополнительные символы новой строки в вашем вводе.Этот код отлично подходит для анализа файла, разделенного запятыми ...

...