Embedded C++: używać STL czy nie?

Zawsze byłem inżynierem oprogramowania wbudowanego, ale zwykle na warstwie 3 lub 2 stosu OSI. Nie jestem facetem od sprzętu. Generalnie zawsze robiłem produkty telekomunikacyjne, zazwyczaj ręcznie / telefony komórkowe, co ogólnie oznacza coś w rodzaju procesora ARM 7.

Teraz znajduję się w bardziej ogólnym świecie wbudowanym, w małym start-upie, gdzie mogę przejść do" nie tak potężnych " procesorów (jest trochę subiektywny) - nie mogę przewidzieć, które.

Przeczytałem sporo o dyskusja na temat używania STL w C++ w systemach embedded i nie ma jednoznacznej odpowiedzi. Istnieją pewne małe obawy o przenośność, a kilka o rozmiar kodu lub czas wykonywania, ale mam dwa główne obawy:
1-obsługa wyjątków; nadal nie jestem pewien, czy go używać (zobacz Embedded C++: używać WYJĄTKÓW czy nie?)
2-zdecydowanie nie lubię dynamicznej alokacji pamięci w systemach wbudowanych, ze względu na problemy, które może wprowadzić. Generalnie mam pulę bufora która jest statycznie przydzielany w czasie kompilacji i który służy tylko buforom o stałej wielkości (jeśli nie ma buforów, reset systemu). STL, oczywiście, robi dużo dynamicznej alokacji.

Teraz muszę podjąć decyzję, czy użyć lub zrezygnować z STL - dla całej firmy, na zawsze (to idzie do jakiegoś bardzo podstawowego s/w).

W którą stronę skoczyć? Super-bezpieczne i stracić wiele z tego, co stanowi C++ (imo, to coś więcej niż tylko definicja języka) i może napotkać problemy później lub trzeba dodać wiele obsługa wyjątków i może jakiś inny kod?

Kusi mnie, aby po prostu przejść z Boost , Ale 1) nie jestem pewien, czy będzie to port do każdego wbudowanego procesora, którego mogę chcieć użyć i 2) na ich stronie internetowej mówią, że nie gwarantują/nie polecają niektórych jego części dla systemów wbudowanych (zwłaszcza FSMs, co wydaje się dziwne). Jeśli pójdę na Boost i znajdziemy problem później ....

Author: Community, 2010-02-09

11 answers

Super-bezpieczne i stracić wiele z tego, co C++ (imo to coś więcej niż tylko definicja języka) i może napotkać później problemy lub mieć aby dodać obsługę wielu WYJĄTKÓW & może jakiś inny kod?

Mamy podobną debatę w świecie gry i ludzie schodzą po obu stronach. Jeśli chodzi o cytowaną część, dlaczego miałbyś się obawiać utraty " dużej części tego, co stanowi C++"? Jeśli to nie jest pragmatyczne, nie używaj tego. Nie powinno mieć znaczenia czy to " C++" albo i nie.

Przeprowadzić kilka testów. Czy możesz obejść zarządzanie pamięcią STL w sposób, który cię zadowoli? Jeśli tak, to czy było warto? Wiele problemów STL i boost są przeznaczone do rozwiązania po prostu nie pojawiają się, jeśli projektujesz, aby uniknąć przypadkowego dynamicznego alokacji pamięci... czy STL rozwiązuje konkretny problem, z którym się stykasz?

Wiele osób zmagało się z STL w ciasnych środowiskach i było z tego zadowolonych. Wielu ludzi po prostu tego unika. Niektórzy proponują zupełnie nowe standardy . Nie sądzę, żeby była jedna właściwa odpowiedź.
 31
Author: Dan Olson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-09 02:22:13

Pracuję na systemach wbudowanych w czasie rzeczywistym każdego dnia. Oczywiście moja definicja systemu wbudowanego może być inna niż Twoja. Ale w pełni wykorzystujemy stl i wyjątki i nie doświadczamy żadnych niemożliwych do opanowania problemów. Korzystamy również z pamięci dynamicznej (z bardzo dużą szybkością; przydzielanie wielu pakietów na sekundę itp. ) i nie trzeba jeszcze uciekać się do żadnych niestandardowych alokatorów lub pul pamięci. Użyliśmy nawet C++ w programach obsługi przerwań. Nie używamy boost, ale tylko dlatego, że pewne agencja rządowa nam nie pozwoli.

Z naszego doświadczenia wynika, że możesz korzystać z wielu nowoczesnych funkcji C++ w środowisku wbudowanym tak długo, jak długo używasz swojej głowy i przeprowadzasz własne benchmarki. Gorąco polecam skorzystanie ze Scotta Meyera Effective C++ 3rd edition, a także Sutter i Alexandrescu C++ Coding Standards aby pomóc ci w użyciu C++ z rozsądnym stylu programowania.

Edit: po uzyskaniu pozytywnej opinii na ten temat 2 lata później, pozwól mi opublikować aktualizację. My są znacznie dalej w rozwoju i w końcu trafiliśmy na miejsca w naszym kodzie, gdzie standardowe kontenery biblioteczne są zbyt wolne w warunkach wysokiej wydajności. Tutaj w rzeczywistości uciekliśmy się do niestandardowych algorytmów, puli pamięci i uproszczonych kontenerów. Na tym polega piękno C++, możesz jednak użyć standardowej biblioteki i uzyskać wszystkie dobre rzeczy, które zapewnia w 90% przypadków użycia. Nie wyrzucasz wszystkiego, gdy napotykasz problemy, po prostu ręcznie optymalizujesz miejsca problemów.

 37
Author: Brian Neal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-02 23:10:28

Pozostałe posty dotyczyły ważnych kwestii dynamicznej alokacji pamięci, wyjątków i możliwego nadcięcia kodu. Chcę tylko dodać: nie zapomnij o <algorithm>! Niezależnie od tego, czy używasz wektorów STL, czy zwykłych tablic i wskaźników C, nadal możesz używać sort(), binary_search(), random_shuffle(), Funkcje do budowy i zarządzania hałd itp. Te procedury będą prawie na pewno szybsze i mniej wadliwe niż wersje, które sam zbudujesz.

Przykład: chyba, że dobrze się nad tym zastanowisz, a algorytm shuffle, który sam zbudujesz , prawdopodobnie wytworzy Przekrzywione dystrybucje; random_shuffle() Nie.

 23
Author: j_random_hacker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:17

Electronic Arts napisało długi traktat o tym, dlaczego STL był nieodpowiedni dla rozwoju konsoli embedded i dlaczego musieli pisać własne. Jest to szczegółowy artykuł, ale najważniejsze powody były następujące:

  1. alokatory STL są powolne, nadęte, i nieefektywne
  2. Kompilatory nie są w rzeczywistości zbyt dobre w inlining wszystkich tych głębokich wywołań funkcji
  3. alokatory STL nie obsługują jawnego wyrównania
  4. algorytmy STL, które pochodzą z GCC i MSVC STL nie są bardzo wydajne, ponieważ są bardzo agnostykami platformy, a tym samym tracą wiele mikrooptymizacji, które mogą zrobić dużą różnicę.

Kilka lat temu nasza firma podjęła decyzję, aby w ogóle nie używać STL, zamiast tego wdrożyła nasz własny system kontenerów, które są maksymalnie wydajne, łatwiejsze do debugowania i bardziej zachowawcze w pamięci. To było dużo pracy, ale spłacił się wiele razy. Ale nasza jest przestrzenią, w której produkty konkurują o to, ile mogą do 16,6 ms z podanym rozmiarem procesora i pamięci.

Co do wyjątków: są powolne na konsolach, a każdy, kto mówi inaczej, nie próbował ich odmierzyć. Po prostu kompilacja z włączoną obsługą spowalnia cały program ze względu na niezbędny kod prolog/epilog-zmierz go sam, jeśli mi Nie wierzysz. Jest jeszcze gorzej na procesorach in-order niż na x86. Z tego powodu kompilator, którego używamy, nie obsługuje nawet WYJĄTKÓW w C++.

The performance gain to nie tyle z unikania kosztów wyrzucenia WYJĄTKÓW - to z całkowitego wyłączenia WYJĄTKÓW.

 19
Author: Crashworks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 01:21:48

Zacznę od tego, że nie robiłem embedded ' u od kilku lat i nigdy w C++, więc moja rada jest warta każdego grosza, który za nią płacisz...

Szablony używane przez STL nigdy nie będą generować kodu, którego nie trzeba by samemu wygenerować, więc nie martwiłbym się o nadęty kod.

STL nie wyrzuca WYJĄTKÓW samodzielnie, więc to nie powinno być problemem. Jeśli twoje zajęcia nie rzucają, powinieneś być bezpieczny. Podziel inicjalizację obiektu na dwie części, niech konstruktor utworzy obiekt bare bones, a następnie wykona inicjalizację, która może się nie udać w funkcji członka, która zwraca kod błędu.

Myślę, że wszystkie klasy kontenerów pozwolą ci zdefiniować własną funkcję alokacji, więc jeśli chcesz przydzielić z puli, możesz to zrobić.

 14
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-09 02:12:40
  1. Do zarządzania pamięcią można zaimplementować własny alokator, który żąda pamięci z puli. I wszystkie kontenery STL mają szablon dla alokatora.

  2. W przypadku WYJĄTKÓW, STL nie wyrzuca wielu WYJĄTKÓW, ogólnie rzecz biorąc, najczęściej są to: out of memory, w Twoim przypadku system powinien się zresetować, więc możesz zrobić reset w alokatorze. inne są takie jak poza zasięgiem, można go uniknąć przez użytkownika.

  3. Więc myślę, że można użyć STL w systemie embedded :)

 5
Author: ddh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-09 05:57:08

To w zasadzie zależy od Twojego kompilatora i ilości posiadanej pamięci. Jeśli masz więcej niż kilka Kb pamięci ram, posiadanie dynamicznej alokacji pamięci bardzo pomaga. Jeśli implementacja malloc z biblioteki standardowej, którą posiadasz, nie jest dostosowana do rozmiaru twojej pamięci, możesz napisać swój własny, lub istnieją ładne przykłady, takie jak mm_malloc z Ralpha Hempela, których możesz użyć do napisania nowych i usuniętych operatorów na górze.

Nie zgadzam się z tymi, którzy powtarzają mem że wyjątki i kontenery stl są zbyt wolne, lub zbyt nadęte itp. Oczywiście dodaje trochę więcej kodu niż zwykłe C ' S malloc, ale rozsądne użycie wyjątków może sprawić, że kod będzie dużo jasny i uniknie zbyt dużego błędu sprawdzania blurb w C.

Należy pamiętać, że alokatory STL zwiększą swoje alokacje w mocach dwóch, co oznacza, że czasami dokonają pewnych realokacji, dopóki nie osiągną odpowiedniego rozmiaru, któremu można zapobiec za pomocą reserve , więc staje się tak tani, jak jeden malloc pożądanego rozmiaru, jeśli znasz rozmiar, który chcesz przydzielić.

Jeśli na przykład masz duży bufor w wektorze, w pewnym momencie może on dokonać realokacji i kończy się zużyciem do 1,5 x rozmiaru pamięci, który zamierzasz użyć w pewnym momencie podczas realokacji i przenoszenia danych. (Na przykład, w pewnym momencie ma przydzielone N bajtów, dodajesz dane za pomocą iteratora dołączania lub wstawiania i przydziela 2N bajtów, kopiuje pierwsze n i zwalnia N. Masz przydzielone 3N bajtów w pewnym momencie pkt).

Więc w końcu ma wiele zalet i opłaca się, jeśli wiesz, co robisz. Powinieneś wiedzieć trochę o tym, jak działa C++, aby używać go w projektach wbudowanych bez niespodzianek.

A dla faceta ze stałymi buforami i resetem, zawsze możesz zresetować wewnątrz nowego operatora lub cokolwiek, jeśli nie masz pamięci, ale oznaczałoby to, że zrobiłeś zły projekt, który może wyczerpać twoją pamięć.

Wyjątek wyrzucany z ARM realview 3.1:

--- OSD\#1504 throw fapi_error("OSDHANDLER_BitBlitFill",res);
   S:218E72F0 E1A00000  MOV      r0,r0
   S:218E72F4 E58D0004  STR      r0,[sp,#4]
   S:218E72F8 E1A02000  MOV      r2,r0
   S:218E72FC E24F109C  ADR      r1,{pc}-0x94 ; 0x218e7268
   S:218E7300 E28D0010  ADD      r0,sp,#0x10
   S:218E7304 FA0621E3  BLX      _ZNSsC1EPKcRKSaIcE       <0x21a6fa98>
   S:218E7308 E1A0B000  MOV      r11,r0
   S:218E730C E1A0200A  MOV      r2,r10
   S:218E7310 E1A01000  MOV      r1,r0
   S:218E7314 E28D0014  ADD      r0,sp,#0x14
   S:218E7318 EB05C35F  BL       fapi_error::fapi_error   <0x21a5809c>
   S:218E731C E3A00008  MOV      r0,#8
   S:218E7320 FA056C58  BLX      __cxa_allocate_exception <0x21a42488>
   S:218E7324 E58D0008  STR      r0,[sp,#8]
   S:218E7328 E28D1014  ADD      r1,sp,#0x14
   S:218E732C EB05C340  BL       _ZN10fapi_errorC1ERKS_   <0x21a58034>
   S:218E7330 E58D0008  STR      r0,[sp,#8]
   S:218E7334 E28D0014  ADD      r0,sp,#0x14
   S:218E7338 EB05C36E  BL       _ZN10fapi_errorD1Ev      <0x21a580f8>
   S:218E733C E51F2F98  LDR      r2,0x218e63ac            <OSD\#1126>
   S:218E7340 E51F1F98  LDR      r1,0x218e63b0            <OSD\#1126>
   S:218E7344 E59D0008  LDR      r0,[sp,#8]
   S:218E7348 FB056D05  BLX      __cxa_throw              <0x21a42766>

Nie wydaje się to takie przerażające i nie dodaje się narzutu wewnątrz {} bloków lub funkcji, jeśli wyjątek nie zostanie wyrzucony.

 3
Author: piotr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-09 07:14:12

Oprócz wszystkich komentarzy, proponuję przeczytanie raportu technicznego na temat wydajności C++ , który konkretnie porusza tematy, które Cię interesują: korzystanie z C++ w wbudowanych (w tym twardych systemach czasu rzeczywistego); jak obsługa wyjątków jest zwykle implementowana i jakie narzuty ma; narzuty alokacji wolnego sklepu.

Raport jest naprawdę dobry, podobnie jak demaskuje wiele popularnych ogonów o wydajności C++.

 3
Author: Alexander Poluektov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-09 10:36:03

[2]} projekt open source " Embedded Template Library (ETL)" rozwiązuje typowe problemy z STL używanym w aplikacjach wbudowanych, dostarczając/implementując bibliotekę:

  • deterministyczne zachowanie
  • " Utwórz zestaw kontenerów, w których rozmiar lub maksymalny rozmiar jest określony podczas kompilacji. Kontenery te powinny być w dużej mierze równoważne kontenerom dostarczanym w STL, z kompatybilnym API."
  • Brak dynamicznej alokacji pamięci
  • no RTTI wymagane
  • niewielkie wykorzystanie funkcji wirtualnych (tylko wtedy, gdy jest to absolutnie konieczne)
  • zestaw pojemników o stałej pojemności
  • przyjazne dla pamięci podręcznej przechowywanie kontenerów jako stale przydzielany blok pamięci
  • Zredukowany rozmiar kodu kontenera
  • typesafe smart enumerations
  • obliczenia CRC
  • sumy kontrolne i funkcje hashowe
  • warianty = rodzaj bezpiecznych związków typu
  • Wybór twierdzeń, WYJĄTKÓW, obsługa błędów lub brak kontroli błędów
  • tested
  • dobrze udokumentowany kod źródłowy
  • i inne funkcje...

Możesz również rozważyć komercyjne C++ STL dla Wbudowanych programistów Dostarczone przez E. S. R. Labs.

 3
Author: thinwybk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-10 09:23:18

Największym problemem STL w systemach wbudowanych jest problem z alokacją pamięci (co, jak powiedziałeś, powoduje wiele problemów).

Chciałbym poważnie zbadać tworzenie własnego zarządzania pamięcią, zbudowanego przez nadpisanie nowych operatorów / delete. Jestem pewien, że z odrobiną czasu można to zrobić i prawie na pewno warto. Co do kwestii WYJĄTKÓW, to bym tam nie poszedł. Wyjątkami są poważne spowolnienie Twojego kodu, ponieważ powodują one każde block ({ }), aby mieć kod przed i po, pozwalający na przechwycenie wyjątku i zniszczenie wszelkich obiektów w nim zawartych. Nie mam twardych danych na ten temat pod ręką, ale za każdym razem, gdy widziałem ten problem, widziałem przytłaczające dowody ogromnego spowolnienia spowodowanego użyciem WYJĄTKÓW.

Edit:
Ponieważ wiele osób napisało komentarze stwierdzające, że obsługa wyjątków jest , a nie wolniejsza, pomyślałem, że dodam tę notkę (dzięki dla osób, które napisały to w komentarzach, pomyślałem, że dobrze będzie dodać to tutaj).

Obsługa wyjątków spowalnia Kod, ponieważ kompilator musi upewnić się, że każdy blok ({}), z miejsca, w którym jest wyrzucany wyjątek do miejsca, w którym jest rozpatrywany, musi dealokować wszystkie obiekty w nim zawarte. Jest to kod, który jest dodawany do każdego bloku, niezależnie od tego, czy ktoś kiedykolwiek wyrzuci wyjątek, czy nie (ponieważ kompilator nie może powiedzieć w czasie kompilacji, czy ten blok będzie częścią wyjątku "łańcuch").

Oczywiście, może to być stary sposób robienia rzeczy, które stały się znacznie szybsze w nowszych kompilatorach (nie jestem dokładnie na bieżąco z optymalizacjami kompilatorów C++). Najlepszym sposobem na poznanie jest uruchomienie przykładowego kodu, z wyjątkami włączonymi i wyłączonymi (i który zawiera kilka zagnieżdżonych funkcji), a różnica czasu.

 1
Author: Edan Maor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-09 04:52:06

W naszym projekcie wbudowanego skanera opracowywaliśmy płytę z procesorem ARM7 i STL nie przyniósł żadnych problemów. Z pewnością szczegóły projektu są ważne, ponieważ dynamiczna alokacja pamięci może nie być problemem dla wielu dostępnych obecnie płyt i typów projektów.

 1
Author: mEbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-19 18:16:54