IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Ракета и Цель., Хаос происходящий в потоках. c++/minGW
сообщение
Сообщение #1


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


Есть желание написать программу, реализующую действия ракеты и её цели. Задаются координаты цели для ракеты, стрелками на клавиатуре можно менять положение цели в 2-х мерном пространстве, ракета должна отслеживать цель. Все это должно производиться "параллельно"..

Код исходный большой(т.е там файлов листинга просто много). Я знаю, что один вольво отвечает на мои безумные посты, на него и надежда вся.smile.gif
В общем, в коде я оставил комментарии, где происходит "неконтролируемое", они в 2х файлах main и realiz.cpp. Код в архиве...

Сообщение отредактировано: Andrewshkovskii -


Прикрепленные файлы
Прикрепленный файл  ev.zip ( 3.04 килобайт ) Кол-во скачиваний: 200
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


с одной проблемой в case разобрался. совсем забыл про brake...А вот почему поток изменения координаты мешени не вызывается - не пойму..:/

Сообщение отредактировано: Andrewshkovskii -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Гость






А можно объяснить, что ты задумывал сделать вот тут:
	switch (choise)
{
case 'n':
std::cout << "Exiting..";
exit(20);
case 'y':
Target target(sx, sy);
p.tarp = &target;
rocket.LockTarget(target.GetXCoord(), target.GetYCoord());
myEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
SetEvent(myEvent);
MyEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
SetEvent(MyEvent2);
while (target.TStatus)
{
if (kbhit() != 0)
{
key = getch();
TH2=CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE) ChangeCoordTarget, &target, 0, &ID); }
TH=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE) MoveToTarget, &p, 0, &ID);
}
}

, желательно - построчно... Особенное внимание, если можно, обратить на ПОСТОЯННОЕ создание потока MoveToTarget. Сколько их у тебя создается? Что делает каждый из них?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


switch (choise)
{
case 'n':// если ответ - n - выходим из программы.
std::cout << "Exiting..";
exit(20);
case 'y':
Target target(sx, sy);// создается объект класса Target
p.tarp = &target;//полю tarp ,структуры содержащей указатели на классы Rocket и Target, //присваевается адрес объекта target
rocket.LockTarget(target.GetXCoord(), target.GetYCoord());//позиционируем координаты цели
myEvent = CreateEvent(NULL, FALSE, FALSE, NULL);//инициализация события для функции изменения //координаты цели
SetEvent(myEvent);//сброс , что бы не тормозить потоки.
MyEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);//для изменения координаты ракеты
SetEvent(MyEvent2);
while (target.TStatus)//цикл пока жива цель
{
if (kbhit() != 0)//если была нажата клавища
{
key = getch();//считать её в переменную key
TH2=CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE) ChangeCoordTarget, &target, 0, &ID);//поток обрабатывает нажатие клавиши и перемешает цель
}
TH=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE) MoveToTarget, &p, 0, &ID);//ракета постоянно контролирует положение цели и стремиться к ней.
}
}

Такая вот задумка.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


Одну проблему нашел, где вычисляется соотношение координаты ракеты и координаты цели. сейчас пытаюсь исправить. Голова плохо варит, спал 4 часа..на рыбалку ездилsmile.gif)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гость






Задумка неплохая, НО... Объясни мне, зачем у тебя потоки создаются, делают одно действие, и удаляются?

Я бы сделал так: Запускаешь сразу после того как ввел координаты цели, оба потока. Функции обоих потоков зацикливаешь, чтобы они не завершались, до тех пор, пока... Ну, например, пока цель не будет сбита (в этот момент какой-нибудь глобальный флажок перебросится в TRUE, и оба потока завершатся). А потом в основном потоке приложения уже читаешь клавишу, записываешь ее коды (да, да... Именно коды, все кнопки управления курсором возвращают 2 байта, первый = 0, второй - то, что ты обрабатываешь), на время изменения переменной, хранящей код нажатой клавиши, устанавливаешь событие, блокируя потоку ChangeCoordTarget доступ к этой переменной, пускай в это время он ждет снятия события (второй поток в это время может продолжать работать, его ничего не должно держать), а потом, как только переменная key "разблокирована", поток ChangeCoordTarget опять продолжает работать: читает содержимое key, и, если оно не = 0, изменяет позицию цели... Поскольку и один и второй поток у тебя работает с данными через указатели, то следующий же цикл чтения потоком MoveToTarget уже будет работать с обновленными координатами цели.

Единственное что, тебе понадобится сделать еще временную блокировку потока MoveToTarget на то время, пока изменяются координаты цели...

Понимаешь идею, или не совсем? У тебя что-то похожее, но не надо постоянно создавать/уничтожать потоки, и не надо блокировать работу одного потока на ВЕСЬ цикл работы другого, достаточно запретить им обращаться к одной и той же переменной в разных режимах (когда один - пишет, другой - читает)
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


Честно говоря не совсем. НЕ совсем я понимаю в синхронизации/блокировке потоков. Просто очень мало с этим работаю. Допустим у меня будет одна булевая переменная , назовем её ISALIVE; Цикл идет while(ISALIVE). это ясно.
Потом, как мне БЛОКИРОВАТЬ поток?с пом-щью wait-функций?
Не понял про коды smile.gif проверять надо по hex-кодам?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гость






Смотри... Я ничего не менял в файлах Rocket.cpp и Target.cpp... Вот все изменения, которые я сделал:

1) файл func.h добавлены описания:
extern char key;
extern bool IsAlive;

extern HANDLE changeKeyEvent;
extern HANDLE startEvent;
, все эти переменные определены в main.cpp

2) файл func.cpp полностью:
#include "func.h"

bool ChangeCoordTarget(Target &tr)
{
WaitForSingleObject(startEvent, INFINITE);
SetEvent(startEvent);
while(IsAlive) {
WaitForSingleObject(changeKeyEvent, INFINITE);
if(key != 0) {
// ResetEvent(changeCoordEvent);
cout << (int)key << endl;
switch (key) {
case 72: // up
tr.y++;
std::cout << "\nY now : " << tr.y << '\n';
break;
case 80: //down
tr.y--;
std::cout << "\nY now : " << tr.y << '\n';
break;
case 75: //left
tr.x--;
std::cout << "\nX now : " << tr.x << '\n';
break;
case 77: // right
tr.x++;
std::cout << "\nX now : " << tr.x << '\n';
break;
}
// SetEvent(changeCoordEvent);
key = 0;
}
Sleep(10);
}
return true;
}


bool MoveToTarget(pointers& p)
{
WaitForSingleObject(startEvent, INFINITE);
SetEvent(startEvent);
while(IsAlive) {
p.rocp->GetRealTimeTCoord(p.tarp);
if (p.rocp->x != p.tarp->x)
if (p.tarp->x < 0) p.rocp->x--;
else p.rocp->x++;

if (p.rocp->y != p.tarp->y)
if (p.tarp->y < 0) p.rocp->y--;
else p.rocp->y++;

cout << "Missile: " << p.rocp->x << " ," << p.rocp->y << endl;
Sleep (1000); // <--- Изменить, а то не совсем честно получается - ракета медленно летит
p.rocp->Hit(p.tarp->TStatus);
if(!p.tarp->TStatus) {
IsAlive = false;
}
}
return true;
}


3) основной цикл файла main.cpp (после согласия выпустить ракету):
		rocket.LockTarget(target.GetXCoord(), target.GetYCoord());
startEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

changeKeyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);

TH2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ChangeCoordTarget,
&target, 0, &ID); // поток обработки изменения координаты цели
TH = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE) MoveToTarget,
&p, 0, &ID); // ракета постоянно контролирует положение цели и стремится к ней.

SetEvent(startEvent);
int ch;
while(kbhit()) getch();

while(IsAlive) {
if(kbhit()) {
if((ch = getch()) == 224) { // Откуда взялось 224 - не понял, всегда был 0
ResetEvent(changeKeyEvent);
key = getch();
SetEvent(changeKeyEvent);
}
else {
if(ch == 27) {
IsAlive = false;
}
}
}
Sleep(50);
}
} // switch(choise)
Если нужны комментарии - скажи, я суть позже добавлю.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


ну интересуют все закомментированные инструкции, в частности:
// switch(choise) - просто забыл убрать?smile.gif
//Set и Reset Event - делал для теста,так я понимаю?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Гость






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

Насчет Set/ResetEvent внутри ChangeCoordTarget() - не то, чтобы для теста, оно таки должно там быть. Пока у тебя пауза в одном потоке в 100 раз больше, чем в другом - практически нереально, чтобы в тот самый момент, когда один поток переменную меняет, другой ее считывал. Как только длительности Sleep-ов приблизятся друг к другу, вероятность такого события будет все выше и выше, и тебе с уменьшением паузы при полете ракеты придется раскомментировать Set/ResetEvent, а в начале цикла while(IsAlive) добавить ожидание этого события, по тому же принципу, как это сделано в ChangeCoordTarget()...

А теперь у меня вопрос на засыпку тебе, раз ты не спросил сам smile.gif

	WaitForSingleObject(startEvent, INFINITE);
SetEvent(startEvent);
и в начале потока ChangeCoordTarget, и в начале потока MoveToTarget(). Почему? Зачем? Что будет, если не делать SetEvent?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


я сделал такое лицо сейчас - dry.gif
У меня лишь предположение, что потоки не начнут свою работу?..

Добавлено через 3 мин.
Черт. я перестал вообще понимать что происходит. Тупо, често, вот сейчас тупо вставил твой код, попробывал "поиграться" и...приложение завершается , так сказать, не успев начаться. Я так понимаю надо добавить ивенты для смены координат...?или я ничего не понимаю.. mad.gif
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Гость






Цитата(Andrewshkovskii @ 18.12.2008 23:08) *
вот сейчас тупо вставил твой код, попробывал "поиграться" и...приложение завершается , так сказать, не успев начаться. Я так понимаю надо добавить ивенты для смены координат...?или я ничего не понимаю.. mad.gif

Я надеюсь, ты не забыл, что надо инициализировать IsAlive?
bool IsAlive = true;
Иначе оно инициализируется false, и "Усе пропало, шеф!!!" (С) "Бриллиантовая рука"

Добавлено через 1 мин.
Цитата
У меня лишь предположение, что потоки не начнут свою работу?..
Неправильно smile.gif Думай дальше...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


Volvo, скажу одно - тебе можно только позавидовать, у тебя столько практики в логике и кодинге..а ладно.щас подумаю получше.


Добавлено через 18 мин.
Ну, видимо, если убрать SetEvent ,допустим, в ChangeCoordTarget, то поток с "полетом ракеты" не узнает о том, что координата поменялась ...
Кстате, почему-то, если добавить строчку в

...
case 77: // right
tr.x++;
break;
}
// SetEvent(changeCoordEvent);
key = 0;
std::cout << "Target now on " << tr.x << " : " << tr.y;//!!!тут
}

То выводиться ascii код нажатой клавиши.
ЕЩё одно..почему-то ракета не летит за целью, а просто перебирает координаты(x++,y--).
Условие я такое поставил :
if (p.rocp->x != p.rocp->TX)//если координата ракеты != коориданты цели
if (p.rocp->x < p.rocp->TX)//если координата Х ракеты меньше коориданты Х цели
if (p.rocp->TX < 0)//проверить, отрицательная или положительная координата х у ракеты
p.rocp->x++;//тогда сместить к цели
else
p.rocp->x++;//иначе , если кооридината ракеты выше положительная, то так же сместиться к ней
else if (p.rocp->x > p.rocp->TX)//если ракета находиться выше цели то..
if (p.rocp->TX < 0)//опять проверяем и т.д.тоже самое и координатой Y
p.rocp->x--;
else
p.rocp->x--;

if (p.rocp->y != p.rocp->TY)
if (p.rocp->y < p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y++;
else
p.rocp->y++;
else if (p.rocp->y > p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y--;
else
p.rocp->y--;

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Гость






Цитата
Ну, видимо, если убрать SetEvent ,допустим, в ChangeCoordTarget, то поток с "полетом ракеты" не узнает о том, что координата поменялась ...
Если убрать SetEvent в ChangeCoordTarget, то поток с полетом ракеты никогда не выйдет из ожидания WaitForSingleObject, потому что событие - с автосбросом, как только один WaitFor... его дождался - оно сбрасывается, и если его опять не установить, то больше ни один WaitFor... его не дождется... Обращай на это внимание. Так что SetEvent-ы в обоих потоках нужны для того, чтобы запустить друг друга (твой изначальный ответ был неверен: один поток все-же запустится, а вот какой именно - это решает системный планировщик заданий).

Цитата
почему-то ракета не летит за целью, а просто перебирает координаты(x++,y--).
С твоей функцией у меня ракета снесла 4 цели из 4-х...

Цитата
выводиться ascii код нажатой клавиши.
Не нужен? Убери
            // ResetEvent(changeCoordEvent);
cout << (int)key << endl; // <--- Вот эту строчку


Сообщение отредактировано: volvo -
 К началу страницы 
+ Ответить 
сообщение
Сообщение #15


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


про аски-код - не заметил, извиняюсь.
Странно, но у меня почему-то происходит изменение координат ракеты так, как я описал, а не "правильно.
полный непонимат.
Будто ракета не получает кооридинаты цели.
может я что-не так написал?,,Да нет, ничего такого вроде бы:

bool MoveToTarget(pointers& p)
{
WaitForSingleObject(startEvent, INFINITE);
SetEvent(startEvent);
while (IsAlive)
{
p.rocp->GetRealTimeTCoord(p.tarp);
if (p.rocp->x != p.rocp->TX)
if (p.rocp->x < p.rocp->TX)
if (p.rocp->TX < 0)
p.rocp->x++;
else
p.rocp->x++;
else if (p.rocp->x > p.rocp->TX)
if (p.rocp->TX < 0)
p.rocp->x--;
else
p.rocp->x--;

if (p.rocp->y != p.rocp->TY)
if (p.rocp->y < p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y++;
else
p.rocp->y++;
else if (p.rocp->y > p.rocp->TY)
if (p.rocp->TY < 0)
p.rocp->y--;
else
p.rocp->y--;
// p.rocp->GetRealTimeTCoord(p.tarp);
// if (p.rocp->x != p.tarp->x)
// if (p.tarp->x < 0) p.rocp->x--;
// else p.rocp->x++;
//
// if (p.rocp->y != p.tarp->y)
// if (p.tarp->y < 0) p.rocp->y--;
// else p.rocp->y++;

cout << "\nMissile at : " << p.rocp->x << " ," << p.rocp->y << endl;
Sleep(500); // <--- Изменить, а то не совсем честно получается - ракета медленно летит
p.rocp->Hit(p.tarp->TStatus);
if (!p.tarp->TStatus)
{
IsAlive = false;
}
}
return true;
}


Сообщение отредактировано: Andrewshkovskii -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #16


Гость






Кстати, чтобы ракета наводилась на цель, достаточно:
        if(p.rocp->x > p.rocp->TX) p.rocp->x -= 1;
else if(p.rocp->x < p.rocp->TX) p.rocp->x += 1;

if(p.rocp->y > p.rocp->TY) p.rocp->y -= 1;
else if(p.rocp->y < p.rocp->TY) p.rocp->y += 1;


И еще одно: если ты хочешь, чтобы при выводе из разных потоков информация отображалась именно так, как ты ее выводишь, а не "перемешивалась" - то сначала печатай все в одну строку (sprintf-ом, например, включая и перевод строки), а потом сразу всю строку посылай в cout. Тогда это будет отображаться точно в том виде, в котором ты подразумевал, в консоли... Иначе, если сделать

// в одном потоке
cout << "hello" << " world" << endl;

// в другом потоке
cout << "wow" << endl;

, то вывод может "перемешаться", и получится, скажем, "hellowow\n world\n", или "hello worldwow\n\n", ведь ты посылаешь данные в поток вывода порциями...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #17


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


Про вывод из потоков понятно.НО проблема-то не в выводе,а в том, что ракеты "психует":) по Х летит вверх, по Y вниз,цель игнорирует. У Вас все нормально?..
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #18


Гость






Цитата
проблема-то не в выводе,а в том, что ракеты "психует":) по Х летит вверх, по Y вниз,цель игнорирует.
Мой вариант функции слежения тоже работает стабильно, цели уничтожаются... Значит, ты что-то не сделал...

Вот весь архив: Прикрепленный файл  rckt.zip ( 4.33 килобайт ) Кол-во скачиваний: 347


Проверь...

Сообщение отредактировано: volvo -
 К началу страницы 
+ Ответить 
сообщение
Сообщение #19


Бывалый
***

Группа: Пользователи
Сообщений: 222
Пол: Мужской
Реальное имя: Andrew

Репутация: -  0  +


Missile at : 8 ,-8
missile report: target at 1527825539 : -1916576418
...всё ясно. Забыл присвоить структуре указателей указатель на цель.
Volvo...Огромное спасибо! Я не знаю, что бы я делал без твоих советов!:)
Кстате, кот у тебя на аватарке классныйsmile.gif

Сообщение отредактировано: Andrewshkovskii -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 20.04.2024 3:07
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name