Существует два основных типа многозадачных операционных систем: упреждающие и кооперативные. Оба позволяют определять несколько задач в системе, разница в том, как работает переключение задач. Конечно, с одним ядром-процессором одновременно выполняется только одна задача.
Оба типа многозадачных ОС требуют отдельного стека для каждой задачи. Таким образом, это подразумевает две вещи: во-первых, процессор позволяет размещать стеки в любом месте ОЗУ и, следовательно, имеет инструкции для перемещения указателя стека (SP), то есть нет аппаратного стека специального назначения, как на младшем конце ПОС. Это исключает серии PIC10, 12 и 16.
Вы можете написать операционную систему почти целиком на C, но переключатель задач, на котором перемещается SP, должен быть в сборке. В разное время я писал переключатели задач для PIC24, PIC32, 8051 и 80x86. Кишки все сильно различаются в зависимости от архитектуры процессора.
Второе требование - наличие достаточного объема ОЗУ для нескольких стеков. Обычно для стека требуется не менее пары сотен байт; но даже при 128 байтах на задачу для восьми стеков требуется 1 КБ ОЗУ - хотя вам не нужно выделять один и тот же размер стека для каждой задачи. Помните, что вам нужно достаточно стека для обработки текущей задачи и любых вызовов ее вложенных подпрограмм, но также и стекового пространства для вызова прерывания, так как вы никогда не знаете, когда это произойдет.
Есть довольно простые методы, чтобы определить, сколько стека вы используете для каждой задачи; Например, вы можете инициализировать все стеки к определенному значению, скажем, 0x55, и запустить систему на некоторое время, а затем остановить и исследовать память.
Вы не говорите, какой PIC вы хотите использовать. Большинство PIC24 и PIC32 будут иметь достаточно места для запуска многозадачной ОС; PIC18 (единственный 8-битный PIC, имеющий стеки в ОЗУ) имеет максимальный размер ОЗУ 4K. Так что это довольно сомнительно.
При совместной многозадачности (более простой из двух) переключение задач выполняется только тогда, когда задача «отдает» свой контроль обратно ОС. Это происходит всякий раз, когда задаче необходимо вызвать подпрограмму ОС для выполнения некоторой функции, которую она будет ожидать, например, запрос ввода-вывода или таймер. Это облегчает ОС переключение стеков, так как нет необходимости сохранять все регистры и информацию о состоянии, SP можно просто переключить на другую задачу (если нет других готовых к запуску задач, пустой стек данный контроль). Если текущая задача не требует выполнения вызова ОС, но выполняется некоторое время, она должна добровольно отказаться от управления, чтобы система реагировала.
Проблема с совместной многозадачностью состоит в том, что если задача никогда не откажется от управления, она может перегружать систему. Только он и любые подпрограммы прерывания, которым назначено управление, могут запускаться, поэтому ОС будет казаться заблокированной. Это «кооперативный» аспект этих систем. Если реализован сторожевой таймер, который сбрасывается только при переключении задач, то можно отловить эти ошибочные задачи.
Windows 3.1 и более ранние версии были совместными операционными системами, отчасти поэтому их производительность не была такой высокой.
Упреждающая многозадачность сложнее реализовать. Здесь задачи не обязаны отказываться от управления вручную, но вместо этого каждой задаче может быть предоставлен максимальный промежуток времени для выполнения (скажем, 10 мс), и затем выполняется переключение задачи на следующую выполняемую задачу, если она есть. Для этого необходимо произвольно остановить задачу, сохранить всю информацию о состоянии, а затем переключить SP на другую задачу и запустить ее. Это делает переключатель задач более сложным, требует большего количества стеков и немного замедляет работу системы.
Как для кооперативной, так и для упреждающей многозадачности прерывания могут происходить в любое время, что временно прерывает выполнение задачи.
Как указывает суперкат в комментарии, одним из преимуществ многозадачности, связанной с кооперативом, является то, что легче распределять ресурсы (например, аппаратное обеспечение, такое как многоканальный АЦП, или программное обеспечение, например, изменение связанного списка). Иногда две задачи хотят получить доступ к одному и тому же ресурсу одновременно. При упреждающем планировании ОС могла бы переключать задачи в середине одной задачи с использованием ресурса. Поэтому блокировки необходимы для предотвращения входа другой задачи и доступа к тому же ресурсу. При совместной многозадачности это не нужно, поскольку задача контролирует, когда она самостоятельно вернется в ОС.