Заміна черг у RTOS


12

Для взаємодії між завданнями або для обміну даними між двома завданнями RTOS, ми використовуємо черги. Але проблема з чергами полягає в тому, що вони повільні .... Вони копіюють дані в буфер, потім обробка Mutex, а потім передача даних. Це дратує повільно, якщо вам доведеться передавати великі дані. Інша проблема полягає в тому, якщо до однієї черги можна отримати декілька завдань. Потім зображення стає таким: - Спочатку зачекайте, щоб отримати доступ до черги, потім - внутрішня обробка Mutex черги, а потім передача даних.

Це збільшує накладні витрати на систему. Що може бути ефективною заміною черг?

(Я думаю, це питання не залежить від RTOS, який ми використовуємо. Більшість RTOS обробляють черги лише таким чином)


Що ви маєте на увазі під чергою, до якої можна отримати кілька завдань? Ви маєте на увазі публікацію в черзі чи читання з черги? Кілька завдань повинні мати змогу розміщувати в черзі з мінімальними накладними витратами. RTOS повинен обробляти мутексинг, щоб пост був атомною операцією. Для 99% завдань у вас має бути цикл, який очікує на чергу та обробляє повідомлення. Чергу (як правило) слід читати лише одним завданням. Вам, мабуть, потрібно подивитися на ваш дизайн та те, як ви використовуєте черги, а не замінювати їх.
Ерік

@Erik: Вибачте! Я використовую механізм, який ви згадали .... Я хотів сказати щось інше, і я написав інше .... Я це відредагую !! Дякуємо за вказівку на помилку! Чекаю доступу до черги у своєму коді!
Swanand

Відповіді:


7

Черги діють таким чином, оскільки це безпечна для транзакцій модель транзакцій для взаємодії між завданнями. Ви ризикуєте корупцією даних та / або проблемами власності в будь-якій менш жорсткій схемі.

Ви копіюєте дані в буфер в пам'яті, потім передаючи вказівник з елементами черги, або намагаєтесь передати всі дані в самі елементи черги? Якщо ви не передаєте покажчики, тоді ви отримаєте підвищення продуктивності, роблячи це замість того, щоб пропускати один байт за раз через елементи черги.


2
Я збирався сказати те саме. Якщо ви просто передаєте покажчики на дані в чергах, ви можете збільшити швидкість, але переконайтеся, що ви не закінчите двома потоками, які намагаються використовувати та змінювати дані.
Кортук

Як сказав @Kortuk, мені потрібно "переконайтеся, що ви не закінчите двома потоками, які намагаються використовувати та змінювати дані" ... Що означає збільшення накладних витрат ... Я не хочу багато обробляти! :(
Swanand

Отже, немає такої заміни для черг ... Замість черги даних мені потрібно використовувати Чергу вказівників!
Swanand

1
@Swanand, якщо плануєте свою програму таким чином, що черги є лише односпрямованими (тобто ви ніколи не читаєте одну і ту ж чергу в двох завданнях) і обробляєте дані, збережені в покажчику одразу, а потім звільняєте її, у вас не повинно виникнути проблем із спільним використанням даних. Збільшиться накладні витрати, оскільки вам, можливо, доведеться створити кілька черг, щоб надійно передавати дані туди-назад, але це вартість ведення бізнесу в умовах багатозадачності.
AngryEE

7

Один простий спосіб - поставити покажчик на дані на черзі та споживати дані за допомогою вказівника.

Зауважте, що ви торгуєте безпекою для продуктивності таким чином, оскільки ви повинні переконатися, що:

  1. буфер залишається дійсним, поки споживач не спожив дані
  2. хтось розсилає буфер

Якщо ви не використовуєте динамічно розподілену пам'ять, вам не доведеться розміщувати її, але все-таки потрібно переконатися, що область пам'яті не буде повторно використана до використання даних.


6

Черги без блокування можуть бути реалізовані для випадку одного виробника / одного споживача, і часто ви можете архітектуру свого програмного забезпечення, щоб мінімізувати кількість черг з декількома виробниками або кількома споживачами.

Черга без блоку може бути побудована так: Виділіть масив елементів, які слід передавати, а також два цілі числа, назвіть їх Head та Tail. Head - це індекс в масив, куди буде доданий наступний елемент. Хвіст - це індекс у масиві, з якого наступний елемент доступний для видалення. Завдання виробника зчитує H і T, щоб визначити, чи є можливість додати предмет; записує товар в індекс Н, потім оновлює H. Споживчі завдання зчитують Н і Т, щоб визначити, чи є доступні дані, зчитують дані з індексу Т, а потім оновлюють Т. В основному це буфер кільця, до якого звертаються дві задачі, і Порядок операцій (вставте, потім оновіть H; видаліть, потім оновіть T) забезпечує запобігання пошкодження даних.

Якщо у вас є ситуація з кількома виробниками та одним споживачем, або одним виробником та кількома споживачами, у вас фактично є обмеження ресурсів, і для цього немає нічого іншого, як використовувати синхронізацію, оскільки швидше обмежувач продуктивності бути одиноким виробником / споживачем, ніж накладні операційні системи з механізмом блокування.

Але якщо у вас є кілька виробників І споживачів, варто витратити час (у дизайнерському просторі), щоб побачити, чи не можете ви отримати більш узгоджений механізм зв'язку; у такому випадку, серіалізація всього за допомогою однієї черги, безумовно, робить ефективність черги центральним визначальним показником продуктивності.


1
Я збирався поставити +1 до цього, але ви невірні: черги без блокування можна реалізувати для кількох читачів і авторів, вони просто складніші. (подивіться на статтю Майкла + Скотта про черги без блоку google.com/search?q=michael%20scott%20queue )
Jason S

1
@Jason S - чи спеціально папір Скотта вимагає повторної участі в операціях без вставки та видалення операцій? Якщо так, якщо ви можете витягнути це та опублікувати, будь ласка, зробіть це, це було б безцінним надбанням для багатьох. Читач повинен зазначити, що цитований документ використовує спеціальні інструкції з машини, тоді як моя позиція у вищезгаданому дописі передбачала, що таких інструкцій немає.
JustJeff

1
Так, вартість алгоритмів без блокування зазвичай покладається на CAS або аналогічні інструкції. Але як тут може грати повторна абітурієнтність? Це має сенс для файлів мтексів + блокування, але не для операцій зі структурою даних.
Jason S

2

Ефективну роботу можна отримати у беззаблочній черзі для одного споживача, якщо сама черга містить об'єкти, які є досить маленькими для роботи з ексклюзивним завантаженням, порівнянням-обміном або подібним примітивом, і можна використовувати зарезервоване значення або зарезервовані значення для порожніх слотів черги. Під час запису до черги письменник робить порівняння-обмін, щоб спробувати зберегти свої дані у наступному порожньому слоті; якщо це не вдасться, письменник намагається виконати наступний слот. Хоча черга підтримує вказівник на наступний порожній слот, значення вказівника є "дорадчим". Зауважте, що якщо система використовує порівняльний обмін, а не ексклюзивний навантаження, може знадобитися "сімейство" різних значень "порожній слот". Інакше, якщо між часом письменник знайде порожній слот черги і намагається записати його, інший письменник пише слот, і читач читає його, перший письменник несвідомо поставив би свої дані там, де читач не побачив би їх. Ця проблема не виникає в системах, які використовують навантажувач-ексклюзив, оскільки ексклюзив магазину виявить, що дані були записані, навіть якщо вони були записані до старого значення.


1

Ви можете отримати доступ до черг більш ефективно, записавши зверху в чергу, як правило, більшість RTOS надає підтримку додавання до передньої частини черги, що не вимагає отримання мютексу. Але переконайтеся, що ви використовуєте додавання до передньої черги якомога мінімальніше там, де ви просто хочете виконати дані швидше. Зазвичай структури черг мають обмеження максимального розміру, тому ви не можете ставити всі дані у чергу, отже, проходження покажчика завжди легко.

ура !!


1

Черги не властиві повільно. Реалізація їх може бути.

Якщо ви сліпо копіюєте дані та використовуєте синхронну чергу, ви побачите хіт ефективності.

Як вказали інші плакати, існують альтернативи без замків. Справа "один виробник / один споживач" є простою; Для декількох виробників і споживачів алгоритм безблокової черги Майкла і Скотта (це їх прізвища) є стандартом і використовується як основа для ConcurrentLinkedQueue Java .

Оптимізувати потребу в черзі в певних випадках можливо, але вони надають гарантії одночасності, які зазвичай дають величезні переваги для спрощення систем, дозволяючи розв’язувати завдання.


З статті Майкла та Скотта: "це чіткий алгоритм вибору для машин, які забезпечують універсальний атомний примітив (наприклад, порівняти та замінити або замінити навантаження / зберігати умовно)". Хоча це насправді не може точно зафіксувати потік, тут відбувається форма синхронізації.
JustJeff

ти правий; це може зменшити вимогу одночасності через виключний доступ до бар'єру пам'яті.
Jason S
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.