2013-06-18 2 views
0

Буду очень благодарен, если кто-нибудь может дать мне указатель в правильном направлении для решения этой проблемы, которую я имел за последние два дня: я работаю над программным обеспечением для набора текста для консоль Visual Studio 2010 и должны представлять время и иметь возможность вводить ввод с клавиатуры одновременно.Состояние гонки с манипуляциями с многопоточными консолями в C#

Проблема заключается в том, что метод ReadLine() позволяет писать только тогда, когда поток таймера спал, возможно, я мог бы решить его с помощью делегатов или методов расширенного продолжения задачи, я немного запутался, так как это новые понятия , Вот код (извините за уродливой форматирования):

using System; 
using System.Threading.Tasks; 
using System.Threading; 


namespace Typing_Game_tests 
{ 

    class Input_and_timer_multithread 
    { 
     public static void TimerThread() 
     { 
      for (int i = 1, mins = -1; i <= 1860; i++) 
      { 
       Console.SetCursorPosition(0, 0); 
       if (i % 60 == 1) 
       { 
        mins++; 
       } 

       Console.WriteLine("Timer: " + mins + " minute(s) and " + i % 60 + " seconds elapsed");    

       Console.SetCursorPosition(0, 6); 
       Thread.Sleep(1000); 
      } 
     } 


     static string keysRead; 

     public static void GetInput() 
     { 
      while (Console.ReadKey(true).Key != ConsoleKey.Enter) 
      { 
       Console.SetCursorPosition(0, 6); 
       keysRead = Console.ReadLine(); 
       Console.SetCursorPosition(0, 6); 
      } 

      Console.SetCursorPosition(0, 6); 
      Console.WriteLine(keysRead); 

     } 

     static void Main(string[] args) 
     {    
      Thread timerMain = new Thread(new ThreadStart(TimerThread)); 
      timerMain.Start(); 
      Task getinputMain = new Task(GetInput); 
      getinputMain.Start(); 
     } 
    } 
    } 

Большинство примеров, которые я нашел и изучены есть лямбда-выражения и делегатов, которые являются новыми субъектами я до сих пор есть некоторые трудности понимания и, таким образом, реализации. Было бы проще, если бы я мог остановить поток основного таймера, пока ReadLine() не выполнил свою работу, но это не имело бы смысла; плюс я попытался использовать пространство имен Timers, но у меня была такая же проблема.

Я хотел создать впечатление, что курсор постоянно вводит пользователя, но я до сих пор не нашел способ эффективно переключаться между потоками без их блокировки. Спасибо.

ответ

2

Этот вид кода больше не работает с .NET 4.5. Console.ReadKey() и ReadLine() используют блокировку, которая предотвращает запись других потоков на консоль. Вам нужно будет заменить его, чтобы блокировка больше не выполнялась. Для этого требуется опрос клавиатура с консолью.KeyAvailable. Вот упрощенный метод замены для Console.ReadLine():

static object ConsoleLock = new object(); 

static string ReadString() { 
    var buf = new StringBuilder(); 
    for (; ;) { 
     while (!Console.KeyAvailable) System.Threading.Thread.Sleep(31); 
     lock(ConsoleLock) { 
      var key = Console.ReadKey(true); 
      if (key.Key == ConsoleKey.Enter) { 
       Console.WriteLine(); 
       return buf.ToString(); 
      } 
      else if (key.Key == ConsoleKey.Backspace) { 
       if (buf.Length > 0) { 
        buf.Remove(buf.Length - 1, 1); 
        Console.Write("\b \b"); 
       } 
      } 
      else { 
       buf.Append(key.KeyChar); 
       Console.Write(key.KeyChar); 
      } 
     } 
    } 
} 

Также блокировка на ConsoleLock в вашем другом потоке, который перемещает курсор так, что вывод строго разделены.

+0

+1 Полезно знать о внутренней блокировке в 'ReadKey()', спасибо. – xxbbcc

+0

Спасибо, что поделились своим опытом, я следил за вашими указаниями, но я все равно зашел в тупик, мне придется вернуться к этому проекту через пару месяцев. Grazie. – User567845

Смежные вопросы