Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/21: Рейтинг темы: голосов - 21, средняя оценка - 5.00
 Аватар для CyberPaladin
18 / 16 / 8
Регистрация: 27.05.2017
Сообщений: 118

Как перезапустить поток после нажатия клавиши без исключений

17.12.2018, 20:32. Показов 4442. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый вечер, коллеги.
Я пишу многопоточную консольную змейку для учебного проекта и все отлично работает за исключением концовки программы.

Так вот ПРОБЛЕМА: когда я пытаюсь нажать клавишу для того чтобы повторить игру(т.е. по сути запустить весь игровой цикл заново то программа падает и выдает необработанное исключение типа "System.Threading.ThreadStateExcepti on" вылетает на второй итерации игрового цикла.
Я хочу только запустить поток заново или завершить поток и затем запустить снова, но не знаю что делать(пробовал метод Abort() - не работает все равно(((

Задумка такая, что из метода Main, изначально мы запускаем игровой метод SetArcadeMode() в котором собственно запускаем поток игры в фоновом режиме StreamArcadeGame() который отвечает за игровую логику(ВСЕ ЭТО РАБОТАЕТ!).
Далее когда мы проигрываем(флаг GAMEOVER == false) то прерываем метод потока и возвращаемся в метод SetArcadeMode() где показываем концовку игры и предлагаем сыграть еще раз или завершить по нажатию Esc или N( за это отвечает данный метод):

C#
1
2
3
4
5
6
7
8
9
10
11
12
static bool RepeatGame(bool isGameover)
        {
            if (isGameover)
            {
                keyInfo = Console.ReadKey(true);
                if (keyInfo.Key == ConsoleKey.Escape || keyInfo.Key == ConsoleKey.N) //нормально завершаем игру и саму программу
                return false;
            }
            //backgroundArcade.Join(); //вот тут ошибка
            Console.Clear();
            return true; //если другая клавиша возвращаемся
        }
Вот весь код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
private static Thread backgroundArcade  = new Thread(StreamArcadeGame); //поток игры
/*
   Другой код
*/
static void Main(string[] args)
        {
            /*
              Другой код
            */
            Console.CursorVisible = false;
            Graphics.ShowLogo(); //стартовый экран
 
            while (true) //обработчик нажатия клавиш
                keyInfo = Console.ReadKey(true);
 
                if (keyInfo.Key == ConsoleKey.Escape)
                    Environment.Exit(0); //выход
     
                if (keyInfo.Key == ConsoleKey.D2)
                {
                    for (int i = 0; i < 6; i++)
                    {
                        Graphics.Blink(2); // просто графический эффект
                    }
                    gameMode = Mode.Arcade;
                    break;
                }
                    for (int i = 0; i < 3; i++) //если нажали что-то неправильно
                    {
                        Graphics.Blink(0);
                    }
            }
 
            Console.Clear();
 
            if (gameMode == Mode.Arcade)
                SetArcadeMode(); //исполняем игровой цикл в методе(код ниже)
        }
/*
  Другой код
*/
 
static void StreamArcadeGame() //метод который выполняется потоком в фоновом режиме
        {
            while (!GAMEOVER)
            {
                if (PAUSE)
                {
                    Console.BackgroundColor = ConsoleColor.Blue;
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.SetCursorPosition(30, 12);
                    Console.Write("GAME PAUSED");
 
                    keyInfo = Console.ReadKey(true);
                    while (keyInfo.Key != ConsoleKey.P)
                    {
                        keyInfo = Console.ReadKey(true); //игровая пауза
                    }
 
                    PAUSE = false;
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.SetCursorPosition(30, 12);
                    Console.Write("            ");
                }
 
                for (int i = 1; i < snake.Count; i++)
                {
                    if (head.X == snake[i].X && head.Y == snake[i].Y) //если змейка столкнулась со стенкой или своим телом
                        GAMEOVER = true; //то конец
                }
                if (GAMEOVER) //прерываем игру
                    break; //выходим из цикла
                if (FOODEXIST == false)
                    CreateFood();
                MoveSnake();
                if (head.X == meal.X && head.Y == meal.Y)
                {
                    IEAT = true;
                    score += Convert.ToInt64((Convert.ToDouble(snake.Count) / 3) * 10); //считаем очки
                    Console.SetCursorPosition(63, 0);
                    Console.Write(score); //выводим очки
                }
                if (IEAT)
                {
                    EatFood();
                }
                Thread.Sleep(speed); //тормозим поток
            }
        }
/*
   Другой код
*/
static void SetArcadeMode() 
        {
            do //собственно игровой цикл
            {
                InitiateSnake(); //прорисовка змейки
                DrawField(); //прорисовка поля
 
                Console.SetCursorPosition(3, 0); //установка статистической инфы 1
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.Write("LEVEL 1");
                Console.ForegroundColor = ConsoleColor.White;
 
                Console.SetCursorPosition(56, 0); //установка статистической инфы 2
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.Write("SCORE: ");
                Console.ForegroundColor = ConsoleColor.White;
                Console.SetCursorPosition(63, 0);
                Console.Write(score);
                 //ВОТ СДЕСЬ ВЫЛЕТАЕТ ИСКЛЮЧЕНИЕ ПРИ 2 ИТЕРАЦИИ ЦИКЛА!!
                backgroundArcade.Start(); //запускаем фоновый поток
                backgroundArcade.IsBackground = true; //делаем его фоновым
 
                ControlArcadeGame(); //позволяет пользователю управлять игрой
 
                Console.Clear();
                Graphics.ShowEnd(score, SnakeLength()); //финиш
 
            } while (RepeatGame(GAMEOVER)); //повторяем если не проиграли
            Environment.Exit(0);
        }
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
17.12.2018, 20:32
Ответы с готовыми решениями:

Продолжить выполнение программы только после нажатия определенной клавиши.
Здравствуйте. Столкнулся с проблемой, необходимо приостановить ход программы : txtBoxNameAfter.Text = workingMP3.id3Title; ...

Вывод на экран нескольких разных строк после нажатия рандомной клавиши
Как сделать так, чтобы каждая отдельная строка текста выводилась на экран после очередного нажатия любой клавиши пользователем? То есть...

После нажатия клавиши Enter или нажатия на Button
Помогите пожалуйста.:-[ Задача: После нажатия клавиши Enter или нажатия на Button поле курсора переходит в соответствующий компонент...

8
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
17.12.2018, 20:43
Цитата Сообщение от CyberPaladin Посмотреть сообщение
Как перезапустить поток после нажатия клавиши без исключений
Завершенный поток не может быть перезапущен. Нужно создавать новый экземпляр потока и запускать его.
Кроме того, вам здесь поток вообще не нужен. Игровой цикл вполне можно запускать в основном потоке.
0
 Аватар для CyberPaladin
18 / 16 / 8
Регистрация: 27.05.2017
Сообщений: 118
17.12.2018, 20:59  [ТС]
Storm23, да, в принципе возможно все сделать и без потоков, но таковы требования - приложение должно быть многопоточным!
К тому же я показал лишь часть кода, а на самом деле в моей программе аж 3 потока(не связанных друг с другом) и если переделать без потоков то это много времени займет.
Пожалуйста, подскажите какой метод использовать. Я пробовал Abort() и Join() и не совсем понятно как их правильно применить?? Это мое первое многопоточное приложение и очень запутывает то что потоки во время выполнения программы в разных состояниях еще могут пребывать
0
 Аватар для PoPsa85
814 / 561 / 240
Регистрация: 01.07.2018
Сообщений: 1,818
17.12.2018, 21:11
CyberPaladin, А почему не Task ?
0
 Аватар для Nalik
176 / 124 / 49
Регистрация: 30.11.2012
Сообщений: 1,330
17.12.2018, 21:19
Лучший ответ Сообщение было отмечено CyberPaladin как решение

Решение

Перед запуском создавайте новый экземпляр потока.
C#
1
2
if (backgroundArcade.IsAlive) { backgroundArcade.Abort(); }
backgroundArcade = new Thread(StreamArcadeGame); //поток игры
1
 Аватар для CyberPaladin
18 / 16 / 8
Регистрация: 27.05.2017
Сообщений: 118
18.12.2018, 02:26  [ТС]
Nalik, ваше решение действительно помогло избавится от исключения, но теперь проблема в том что когда после проверки статуса конца игры я нажимаю клавишу отличительную от Esc то консоль сначала прорисовывает всю игру а затем сразу же её завершает(т.е. поток исполняется втупую до конца цикла)

С начала я создавал новый экземпляр потока в проверяющем методе:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static bool RepeatGame(bool isGameover)
        {
            if (isGameover)
            {
                keyInfo = Console.ReadKey(true);
                if (keyInfo.Key == ConsoleKey.Escape || keyInfo.Key == ConsoleKey.N)
                    return false;
                else
                {
                            if (backgroundArcade.IsAlive)
                            {
                                backgroundArcade.Abort();
                                Console.Clear();
                            }
                            backgroundArcade = new Thread(StreamArcadeGame);
                            break;
                } 
            }
            Console.Clear();
            return true;
        }
Затем просто засунул в начало игрового цикла...

Собственно говоря эффект тот же самый - поток летит без остановки.

Добавлено через 5 минут
PoPsa85, по правде говоря, я не углублялся в использование Task-ов, но судя по методам и свойствам этого класса, вся эта тема похожа на Thread. Значит логично предположить что и изменений никаких за собой это не повлечет.
В общем я особо разницы не уловил между Thread и Task
0
 Аватар для Nalik
176 / 124 / 49
Регистрация: 30.11.2012
Сообщений: 1,330
18.12.2018, 08:43
Где-то у вас логическая ошибка. Сможете скинуть проект?
0
 Аватар для CyberPaladin
18 / 16 / 8
Регистрация: 27.05.2017
Сообщений: 118
18.12.2018, 20:38  [ТС]
Nalik, я все же решил последнюю проблему!! И да, вы правы это была логическая.
Я просто забыл после того как создал новый экземпляр потока переставить глобальный флаг GAMEOVER в значение false. Вот и получалось что поток перезапускал игру со статусом GAMEOVER изначально - т.е. рисовал уровень, змейку а в метод управления игнорировался т.к. статус был неправильный.
И вот правильный метод перезапуска игрового цикла с использованием потока:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static bool RepeatGame(bool isGameover)
        {
            if (isGameover)
            {
                keyInfo = Console.ReadKey(true);
                if (keyInfo.Key == ConsoleKey.Escape || keyInfo.Key == ConsoleKey.N)
                    return false;
                else
                {
                            if (backgroundArcade.IsAlive)
                            {
                                backgroundArcade.Abort();
                                Console.Clear();
                            }
                            backgroundArcade = new Thread(StreamArcadeGame); //создаем управляющий поток
                            GAMEOVER = false; //нормализируем игровой статус 
                            break;
                } 
            }
            Console.Clear();
            return true;
        }
Благодарю за то что указали правильное решение!
0
 Аватар для Nalik
176 / 124 / 49
Регистрация: 30.11.2012
Сообщений: 1,330
18.12.2018, 20:49
Супер
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
18.12.2018, 20:49
Помогаю со студенческими работами здесь

После нажатия клавиши, не обрабатывать другие клавиши
На форме по нажатию разных клавиш происходят разные вещи, но хочу реализовать паузу по нажатию пробела, т.е. после нажатия пробела, другие...

Побуквенный вывод слова через цикл + ожидания нажатия клавиши (после нажатия очистка и установка курсора на )
строку) Masm32 (com -программа) вообщем столкнулся с проблемой. к примеру ввожу ' LSD49 $' выводится через цикл loop (в ECX -...

Как сделать повтор действия после нажатия любой клавиши
Задача : Разработать программу, в которой описать переменные для создания соответствующей динамической структуры. Рекомендуется в...

Как отменить дальнейшую обработку нажатия клавиши после перехвата?
Хочу по нажатию Ctrl+P в форме вместо печати формы выводить на печать отчет. Нажатие Ctrl+P перехватила, код: Private Sub...

Как приостановить и перезапустить поток
Есть следующее задание: Написать приложение, содержащее не менее двух тредов. Каждый из этих тредов должен искать файлы: - с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru