1. Пользуйтесь тегами кода. - [code] ... [/code] 2. Точно указывайте язык, название и версию компилятора (интерпретатора). 3. Название темы должно быть информативным. В описании темы указываем язык!!!
Есть желание написать программу, реализующую действия ракеты и её цели. Задаются координаты цели для ракеты, стрелками на клавиатуре можно менять положение цели в 2-х мерном пространстве, ракета должна отслеживать цель. Все это должно производиться "параллельно"..
Код исходный большой(т.е там файлов листинга просто много). Я знаю, что один вольво отвечает на мои безумные посты, на него и надежда вся. В общем, в коде я оставил комментарии, где происходит "неконтролируемое", они в 2х файлах main и realiz.cpp. Код в архиве...
, желательно - построчно... Особенное внимание, если можно, обратить на ПОСТОЯННОЕ создание потока MoveToTarget. Сколько их у тебя создается? Что делает каждый из них?
switch (choise) { case 'n':// если ответ - n - выходим из программы. std::cout << "Exiting.."; exit(20); case 'y': Target target(sx, sy);// создается объект класса Target p.tarp = ⌖//полю 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);//ракета постоянно контролирует положение цели и стремиться к ней. } }
Одну проблему нашел, где вычисляется соотношение координаты ракеты и координаты цели. сейчас пытаюсь исправить. Голова плохо варит, спал 4 часа..на рыбалку ездил)
Задумка неплохая, НО... Объясни мне, зачем у тебя потоки создаются, делают одно действие, и удаляются?
Я бы сделал так: Запускаешь сразу после того как ввел координаты цели, оба потока. Функции обоих потоков зацикливаешь, чтобы они не завершались, до тех пор, пока... Ну, например, пока цель не будет сбита (в этот момент какой-нибудь глобальный флажок перебросится в TRUE, и оба потока завершатся). А потом в основном потоке приложения уже читаешь клавишу, записываешь ее коды (да, да... Именно коды, все кнопки управления курсором возвращают 2 байта, первый = 0, второй - то, что ты обрабатываешь), на время изменения переменной, хранящей код нажатой клавиши, устанавливаешь событие, блокируя потоку ChangeCoordTarget доступ к этой переменной, пускай в это время он ждет снятия события (второй поток в это время может продолжать работать, его ничего не должно держать), а потом, как только переменная key "разблокирована", поток ChangeCoordTarget опять продолжает работать: читает содержимое key, и, если оно не = 0, изменяет позицию цели... Поскольку и один и второй поток у тебя работает с данными через указатели, то следующий же цикл чтения потоком MoveToTarget уже будет работать с обновленными координатами цели.
Единственное что, тебе понадобится сделать еще временную блокировку потока MoveToTarget на то время, пока изменяются координаты цели...
Понимаешь идею, или не совсем? У тебя что-то похожее, но не надо постоянно создавать/уничтожать потоки, и не надо блокировать работу одного потока на ВЕСЬ цикл работы другого, достаточно запретить им обращаться к одной и той же переменной в разных режимах (когда один - пишет, другой - читает)
Честно говоря не совсем. НЕ совсем я понимаю в синхронизации/блокировке потоков. Просто очень мало с этим работаю. Допустим у меня будет одна булевая переменная , назовем её ISALIVE; Цикл идет while(ISALIVE). это ясно. Потом, как мне БЛОКИРОВАТЬ поток?с пом-щью wait-функций? Не понял про коды проверять надо по hex-кодам?
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();
ну интересуют все закомментированные инструкции, в частности: // switch(choise) - просто забыл убрать? //Set и Reset Event - делал для теста,так я понимаю?
Нет-нет... Это как раз для того, чтобы показать тебе, где заканчивается мой фрагмент, и продолжается дальше твой, чтоб ты не подумал, что лишняя закрывающая скобка...
Насчет Set/ResetEvent внутри ChangeCoordTarget() - не то, чтобы для теста, оно таки должно там быть. Пока у тебя пауза в одном потоке в 100 раз больше, чем в другом - практически нереально, чтобы в тот самый момент, когда один поток переменную меняет, другой ее считывал. Как только длительности Sleep-ов приблизятся друг к другу, вероятность такого события будет все выше и выше, и тебе с уменьшением паузы при полете ракеты придется раскомментировать Set/ResetEvent, а в начале цикла while(IsAlive) добавить ожидание этого события, по тому же принципу, как это сделано в ChangeCoordTarget()...
А теперь у меня вопрос на засыпку тебе, раз ты не спросил сам
я сделал такое лицо сейчас - У меня лишь предположение, что потоки не начнут свою работу?..
Добавлено через 3 мин. Черт. я перестал вообще понимать что происходит. Тупо, често, вот сейчас тупо вставил твой код, попробывал "поиграться" и...приложение завершается , так сказать, не успев начаться. Я так понимаю надо добавить ивенты для смены координат...?или я ничего не понимаю..
вот сейчас тупо вставил твой код, попробывал "поиграться" и...приложение завершается , так сказать, не успев начаться. Я так понимаю надо добавить ивенты для смены координат...?или я ничего не понимаю..
Я надеюсь, ты не забыл, что надо инициализировать IsAlive?
bool IsAlive = true;
Иначе оно инициализируется false, и "Усе пропало, шеф!!!" (С) "Бриллиантовая рука"
Добавлено через 1 мин.
Цитата
У меня лишь предположение, что потоки не начнут свою работу?..
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--;
Ну, видимо, если убрать SetEvent ,допустим, в ChangeCoordTarget, то поток с "полетом ракеты" не узнает о том, что координата поменялась ...
Если убрать SetEvent в ChangeCoordTarget, то поток с полетом ракеты никогда не выйдет из ожидания WaitForSingleObject, потому что событие - с автосбросом, как только один WaitFor... его дождался - оно сбрасывается, и если его опять не установить, то больше ни один WaitFor... его не дождется... Обращай на это внимание. Так что SetEvent-ы в обоих потоках нужны для того, чтобы запустить друг друга (твой изначальный ответ был неверен: один поток все-же запустится, а вот какой именно - это решает системный планировщик заданий).
Цитата
почему-то ракета не летит за целью, а просто перебирает координаты(x++,y--).
С твоей функцией у меня ракета снесла 4 цели из 4-х...
Цитата
выводиться ascii код нажатой клавиши.
Не нужен? Убери
// ResetEvent(changeCoordEvent); cout << (int)key << endl; // <--- Вот эту строчку
про аски-код - не заметил, извиняюсь. Странно, но у меня почему-то происходит изменение координат ракеты так, как я описал, а не "правильно. полный непонимат. Будто ракета не получает кооридинаты цели. может я что-не так написал?,,Да нет, ничего такого вроде бы:
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; }
И еще одно: если ты хочешь, чтобы при выводе из разных потоков информация отображалась именно так, как ты ее выводишь, а не "перемешивалась" - то сначала печатай все в одну строку (sprintf-ом, например, включая и перевод строки), а потом сразу всю строку посылай в cout. Тогда это будет отображаться точно в том виде, в котором ты подразумевал, в консоли... Иначе, если сделать
// в одном потоке cout << "hello" << " world" << endl;
// в другом потоке cout << "wow" << endl;
, то вывод может "перемешаться", и получится, скажем, "hellowow\n world\n", или "hello worldwow\n\n", ведь ты посылаешь данные в поток вывода порциями...
Про вывод из потоков понятно.НО проблема-то не в выводе,а в том, что ракеты "психует":) по Х летит вверх, по Y вниз,цель игнорирует. У Вас все нормально?..
Missile at : 8 ,-8 missile report: target at 1527825539 : -1916576418 ...всё ясно. Забыл присвоить структуре указателей указатель на цель. Volvo...Огромное спасибо! Я не знаю, что бы я делал без твоих советов!:) Кстате, кот у тебя на аватарке классный