Консультация № 53142
24.08.2006, 17:14
0.00 руб.
0 6 6
Привет, эксперты. Вот я тут задумался, и у меня возник вопрос. Как реализовать многозадачность или многопоточность (не знаю что правильно)самому на си. Ну к примеру я хочу чтобы у меня играла музыка(простейшая, создаваемая спикером) и одновременно рисовались какие-нибудь фигурки на экране или что нибудь в этом роде, в общем какая-нить графика. Так вот допустим у меня есть функция которая музыку играет PlayMySong(), вот я её вызываю, а далее идёт рисование графики, функция PaintMyShape(). Так всем известно, что пока не отработает первая функция переход ко второй функции не возможен. Звучит странно. Никто не задумывается когда играет в игры что одновременно звучит музыка и сама графика работает- но на это берёт ответственность сама windows, точнее её ядро. А как самому реализовать такую штуку чтобы в консоли работало или под чистым досом. Что почитать посоветуете ?Спасибо.

Обсуждение

давно
Академик
20764
1861
24.08.2006, 17:43
общий
это ответ
Здравствуйте, Александр Михайлович!

Есть два пути:

1. писать приложение так, чтобы оно было event-driven, то есть только реагировало на всевозможные события приходящие извне: от оконной системы, устройств (tнажата клавиша, или буфер звуковой карты освобождается) и т.д. Путь хлопотный, но все GUI программы работают именно так, и соответственные библиотеки такое программирование сильно упрощают.

2. использовать threads Это проще (хотя подводные камни тоже имеются), но требуется, чтобы это поддерживалось в системе.

В любом случае к языку программирования это имеет отношение не слишком большое.
Неизвестный
24.08.2006, 17:47
общий
это ответ
Здравствуйте, Александр Михайлович!

В большом угрублении все выглядит так:
Устанавливаешь обработчик перрываний по таймеру. Он делает:
1. Проверяет, не выполняеться ли при этом критических задач (типа записи на диск), если они идут - доделывает их.
2. Записывает состояние задачи в свою внутреннюю таблицу: регистры процессора, стек, видеоданные
3. Берет из этой таблицы данные к следующей задаче, восстанавливает их и выполняет возврат из прерывания в эту задачу (удаляя из внутренней из таблицы)...

и следующая задача выполняется, пока не установиться прерывание по таймеру, дальше смтри п.1

так и получаеться - таблица текущих задач, которые процессор время от времени запускает. В современных процессорах есть много функции для поддержки такого режима работы.
В играх прерывания и переключения задач идут не только от таймера, а и от нажатой клавиши или окончания звучания отрывка, тогда и запускается соответствующая задача...
Неизвестный
24.08.2006, 19:06
общий
это ответ
Здравствуйте, Александр Михайлович!
Вот консольное приложение (см. приложение).
Считайте что функция PlayMySong() соответствует ThreadFunc1(), а PaintMyShape соответствует ThreadFunc2();
Пример демонстрирует как эти 2 функции работают параллельно.
Думаю, разберетесь.
P.S. Возможно, приведенный код написан не корректно... (но он работает). я писал его только чтобы показать работу потоков...
Удачи!

Приложение:
#include <windows.h>#include <process.h>#include <stdio.h>DWORD WINAPI ThreadFunc1(LPVOID lpParam){ int i; printf("First thread running!\n"); for(i=0; i<10; i++){ printf("1 -> %d\n",i); Sleep(1000); } return 0;}DWORD WINAPI ThreadFunc2(LPVOID lpParam){ int i; printf("Second thread running!\n"); for(i=0; i<10; i++){ printf("2 -> %d\n",i); Sleep(1500); } return 0;}int main(){ HANDLE ArrayThread[2]; HANDLE hThread1,hThread2; hThread1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL); if(hThread1 == NULL) ExitProcess(0); hThread2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL); if(hThread2 == NULL) ExitProcess(0); ArrayThread[0] = hThread1; ArrayThread[1] = hThread2; // Ждем, пока потоки не завершат свою работу WaitForMultipleObjects(2, ArrayThread, TRUE, INFINITE ); // Закрываем дескрипторы CloseHandle(hThread1); CloseHandle(hThread2); return 0;}
Неизвестный
24.08.2006, 19:51
общий
это ответ
Здравствуйте, Александр Михайлович!
Загружаешь музыку и графику в память, затем с помощью таймера в каждый момент времени сначала играешь очередной кусок звука и выводишь очередной кадр графики, используя данные в памяти.
Неизвестный
24.08.2006, 20:38
общий
это ответ
Здравствуйте, Александр Михайлович!

Пара терминов:
Многозадачность - когда могут одновременно выполняться несколько (совершенно различных) программ.
Многопоточность - когда в одной программе имеется несколько потоков выполнения (разделяющих общую память, переменные, код).

Поддержка того и другого зависит от ОС. ДОС не поддерживает ни того, ни другого.

Кроме того, КОНСОЛЬ и ДОС это разные вещи! Консольное приложение - просто приложение, которое использует консольный ввод-вывод. Оно может пользоваться всеми возможностями опреационной системы, в том числе и создавать потоки, обращаться к функциям WinAPI и т.д.

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

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

Как правильно отметили, работа с потоками зависит не столько от языка, сколько от операционной системы. (Отличается разве что Java, там многопоточность может быть реализована собственными средствами)
Неизвестный
25.08.2006, 10:00
общий
это ответ
Здравствуйте, Александр Михайлович!

Ещё добавлю к простыне ответов (ибо уж слишком пного налегают на ОС, а точнее на Windows и систематизирую немного).

Все процессоры, начиная с i80x386 (и некоторые 286) поддерживают многозадачность (расшифровку терминов см. у "Шинтяков Дмитрий Васильевич / Ratson"), а более поздние и многопоточность, на аппаратном уровне (protected mode процессора), поэтому использовать её можно и без всякой операционной системы вообще (но это уже в другую ветку RusFaq.ru). А ОС... - она только в силу своего интеллекта использует аппаратные возможности процессора.

Но мысли приведены верные, существуют такие основные подходы:
1. Через event-handler. Это когда у тебя процедура вызывается по событию.
2. Line-handler. Это когда у тебя работают всегда все процедуры (вызываются в handler‘е по очереди), но не содержат длительных циклов и нигде не замирают, то есть работают по принципу "сделал - изменил семафор - отвалил".
3. Через другой процесс (может быть и дочерним, а может быть и вообще "левым"). Тогда процессы общаются только с помощью внешних разделяемых ресурсов.
4. Через потоки. Это когда несколько подзадач вертятся каждая в своём потоке. Общаются через общие ресурсы (могут и через внешние, только зачем?).
5. Полу-железно. Когда одну из задач выполняет какое-нибудь железо.

... Вроде всё, может ещё чего забыл...

Но, в любом случае - успехов в освоении PC!

Форма ответа