Есть несколько хороших трюков, которые вы можете использовать, чтобы помочь.
Во-первых, хорошая производительность. VxWorks отличается очень хорошим временем переключения контекста. Какое бы решение блокировки вы ни использовали, оно, скорее всего, будет включать семафоры. Я бы не боялся использовать для этого семафоры (множественное число), они довольно хорошо оптимизированы в VxWorks, а быстрое время переключения контекста помогает минимизировать снижение производительности из-за оценки многих состояний семафора и т. д.
Также я бы забыл об использовании семафоров POSIX, которые просто будут располагаться поверх собственных семафоров VxWork. VxWorks предоставляет собственные счетные, двоичные и мьютексные семафоры; использование того, который подходит, делает все немного быстрее. Бинарные иногда могут быть весьма полезными; отправлено много раз, никогда не превышайте значение 1.
Во-вторых, запись важнее чтения. Когда у меня были такие требования в VxWorks и я использовал семафор(ы) для управления доступом, я использовал приоритет задачи, чтобы указать, какая задача важнее и должна получить доступ к ресурсу первой. Это работает довольно хорошо; буквально все в VxWorks это задача (ну и поток) как и любая другая, включая все драйвера устройств и т.д.
VxWorks также разрешает инверсии приоритетов (такие вещи, которые ненавидит Линус Торвальдс). Таким образом, если вы реализуете блокировку с помощью семафора(ов), вы можете положиться на планировщик ОС, который будет блокировать операции чтения с более низким приоритетом, если они блокируют запись с более высоким приоритетом. Это может привести к гораздо более простому коду, и вы также получите максимальную отдачу от ОС.
Таким образом, потенциальное решение состоит в том, чтобы иметь один счетный семафор VxWorks, защищающий ресурс, инициализированный значением, равным количеству читателей. Каждый раз, когда читатель хочет прочитать, он берет семафор (уменьшая счетчик на 1. Каждый раз, когда выполняется чтение, он отправляет семафор, увеличивая счетчик на 1. Каждый раз, когда пишущий хочет записать, он берет семафор n (n = количество читателей) раз и публикует его n раз, когда закончите. Наконец, сделайте задачу записи более приоритетной, чем любой из читателей, и полагайтесь на быстрое время переключения контекста ОС и инверсию приоритета.
Помните, что вы программируете на ОС жесткого реального времени, а не на Linux. Получение/публикация собственного семафора VxWorks не требует такого же количества времени выполнения, как аналогичное действие в Linux, хотя даже Linux в наши дни довольно хорош (я использую PREEMPT_RT в настоящее время). На поведение планировщика VxWorks и всех драйверов устройств можно положиться. Вы даже можете сделать свою задачу записи наивысшим приоритетом во всей системе, если хотите, даже выше, чем у всех драйверов устройств!
Чтобы помочь делу, также подумайте, что делает каждый из ваших потоков. VxWorks позволяет указать, что задача использует или не использует FPU. Если вы используете собственные подпрограммы VxWorks TaskSpawn вместо pthread_create, у вас есть возможность указать это. Это означает, что если ваш поток/задача не выполняет математических вычислений с плавающей запятой, и вы сказали об этом в своем вызове TaskSpawn, время переключения контекста будет еще быстрее, потому что планировщик не будет заботиться о сохранении / восстановить состояние FPU.
Это имеет разумные шансы стать лучшим решением для платформы, на которой вы разрабатываете. Он использует сильные стороны ОС (быстрые семафоры, быстрое время переключения контекста) без добавления дополнительного кода для воссоздания альтернативного (и, возможно, более элегантного) решения, обычно используемого на других платформах.
В-третьих, застрял со старым GCC и старым Boost. По сути, я не могу помочь, кроме малоценных предложений о том, чтобы позвонить в WindRiver и обсудить покупку обновления. Лично говоря, когда я программировал для VxWorks, я использовал собственный API VxWork, а не POSIX. Итак, код не очень переносимый, но в итоге он стал быстрым; В любом случае POSIX — это просто слой поверх собственного API, и это всегда будет замедлять работу.
Тем не менее, семафоры подсчета и мьютекса POSIX очень похожи на собственные семафоры подсчета и мьютекса VxWork. Вероятно, это означает, что слои POSIX не очень толстые.
Общие примечания о программировании для VxWorks
Отладка Я всегда старался использовать инструменты разработки (Tornado), доступные для Solaris. Это, безусловно, лучшая многопоточная среда отладки, с которой я когда-либо сталкивался. Почему? Это позволяет запускать несколько сеансов отладки, по одному для каждого потока/задачи в системе. В итоге вы получаете окно отладки для каждого потока, и вы индивидуально и независимо отлаживаете каждый из них. Перешагнув операцию блокировки, это окно отладки будет заблокировано. Переместите фокус мыши на другое окно отладки, пройдитесь по операции, освобождающей блок, и наблюдайте, как первое окно завершает свой шаг.
В итоге вы получаете множество окон отладки, но это, безусловно, лучший способ отладки многопоточных приложений. Это упростило написание очень сложных вещей и возможность видеть проблемы. Вы можете легко исследовать различные динамические взаимодействия в своем приложении, потому что у вас есть простой и мощный контроль над тем, что делает каждый поток в любое время.
По иронии судьбы версия Tornado для Windows не позволяла вам этого сделать; одно жалкое одиночное окно отладки на систему, как и любая другая скучная старая IDE, такая как Visual Studio и т. д. Я никогда не видел, чтобы даже современные IDE приближались к тому, чтобы быть такими же хорошими, как Tornado на Solaris для многопоточной отладки.
Жесткие диски Если ваши программы чтения и записи используют файлы на диске, учтите, что VxWorks 5.5 устарел. Такие вещи, как NCQ, не будут поддерживаться. В этом случае мое предложенное решение (изложенное выше) может быть лучше реализовано с одним семафором мьютекса, чтобы предотвратить спотыкание нескольких читателей друг о друга в их борьбе за чтение разных частей диска. Это зависит от того, что именно делают ваши читатели, но если они читают непрерывные данные из файла, это позволит избежать тряски головки чтения/записи туда и обратно по поверхности диска (очень медленно).
В моем случае я использовал этот трюк для формирования трафика через сетевой интерфейс; каждая задача отправляла разные типы данных, а приоритет задачи отражал приоритет данных в сети. Это было очень элегантно, ни одно сообщение никогда не фрагментировалось, но важные сообщения получали львиную долю доступной пропускной способности.
person
bazza
schedule
27.01.2015
semMCreate()
(префиксsem
означает семафор) — это именно то, во что мы обернули наш тонкий классmutex
. Переменные условия, однако, мы основывали на бинарных семафорах. Учитывая, что большая часть поддержки POSIX отсутствует, я не вижу большого смысла в использовании semPxLib, который, как вы (?) предложили в другом месте, скорее всего, является просто тонким слоем поверх двоичных семафоров, которые мы могли бы также обернуть сами. - person sbi   schedule 28.01.2015