Ich will gerne std atomic zur Implementierung einer queue benutzen um Daten von einem UART, die per DMA gelesen werden zu verarbeiten. Kann man das sicher benutzen um den Head zeiger auch aus dem Interupt heraus zu verändern?
Ja. Aber probiere erst mal aus, ob der Compiler (bzw. die Standard-C++-Bibliothek) überhaupt genug von std::atomic<T> für Deine gewünschte Anwendung, Deinen gewünschten T und den ARM-Kern der Ziel-MCU unterstützt. Es gibt da einige Lücken.
Zino schrieb: > Ja. Aber probiere erst mal aus, ob der Compiler (bzw. die > Standard-C++-Bibliothek) überhaupt genug von std::atomic<T> für Deine > gewünschte Anwendung, Deinen gewünschten T und den ARM-Kern der Ziel-MCU > unterstützt. Es gibt da einige Lücken. std::atomic ist in der standard C++ library vorhanden und kompiliert zumindest. Was ich mich nur frage ob es da nicht zu deadlocks führen kann wenn man mit load arbeitet, da es ja keinen context switch bei interrupts gibt und wenn ich ein load im interrupt aufrufe was passiert dann?
Es muß nicht nur kompilieren sondern auch linken. Es ist egal, ob Threads oder Interrupts, in std::atomic blockiert nichts außer std::atomic<T>::wait().
Gustav G. schrieb: > std::atomic ist in der standard C++ library vorhanden und kompiliert > zumindest. Was ich mich nur frage ob es da nicht zu deadlocks führen > kann wenn man mit load arbeitet, da es ja keinen context switch bei > interrupts gibt und wenn ich ein load im interrupt aufrufe was passiert > dann? Schau es Dir doch an ;-) std::atomic ist korrekt implementiert, Kannst Du also benutzen: ist ggf. aber zu aufwändig für simple IRQ. Du kannst aber auch ein SeqLock mit LDREX/STREX benutzen für RMW-Folgen. Für Typen einzelne load / store für DT <= 32 Bit sind keine besondere Maßnahmen erforderlich.
:
Bearbeitet durch User
Zino schrieb: > Es muß nicht nur kompilieren sondern auch linken. Es ist egal, ob > Threads oder Interrupts, in std::atomic blockiert nichts außer > std::atomic<T>::wait(). Nur wenn std::atomic<T>::is_lock_free() ja sagt. Sonst greift man ggf. im Interrupt ein Lock mit allen bekannten Folgen.
Hannes W. schrieb: > Nur wenn std::atomic<T>::is_lock_free() ja sagt. Sonst greift man ggf. > im Interrupt ein Lock mit allen bekannten Folgen. In dem Fall ist es lockfree. Kann das bei STM32 mal nicht der Fall sein und wie würde man das abfangen oder beheben. Ich müsste es sonst so machen, dass ich im interrupt einen Puffer schreibe und beim abfragen eben alle interrupts kurzzeitig deaktiviere, was unschön wäre.
Gustav G. schrieb: > Hannes W. schrieb: >> Nur wenn std::atomic<T>::is_lock_free() ja sagt. Sonst greift man ggf. >> im Interrupt ein Lock mit allen bekannten Folgen. > > In dem Fall ist es lockfree. Kann das bei STM32 mal nicht der Fall sein > und wie würde man das abfangen oder beheben. Ich müsste es sonst so > machen, dass ich im interrupt einen Puffer schreibe und beim abfragen > eben alle interrupts kurzzeitig deaktiviere, was unschön wäre. Wie schon gesagt: das Lesen oder Schreiben von 32-Bit Typen ist atomar, auf single-core ist auch keine Laufzeit-Memory-Barrier erforderlich (lediglich ein Compile-Time-Barrier). Wenn Du sicher gehen willst, bau eine statische Zusicherung ein. RMW-Sequenzen auch von <= 32-Bit Typen sind nie atomar. Aber dafür hat der ARM ja auch LDREX/STREX und die Interrupts führen (automatisch) ein CLREX aus (Achtung: nicht jeder STM32 macht das, dann muss man es eben zu Fuß machen. Die std::atomic<> verwenden genau diese Seq-Lock-Sequenz. Ein Abschalten der IRQs ist also nicht notwendig. Da die std::atomic<> aber für Multi-Core geeignet sind, und nicht für Single-Core spezialisiert, kannst Du noch auf die Laufzeit-Memory-Barrier bei Single-Core verzichten:
1 | // 1
|
2 | uint32_t val; |
3 | do { |
4 | val = __LDREXW(&a2); |
5 | val += 1; |
6 | } while ((__STREXW(val, &a2)) != 0U); |
7 | |
8 | // 2
|
9 | std::atomic_fetch_add(&a1, 1); |
10 | |
11 | // 3
|
12 | std::atomic_signal_fence(std::memory_order_seq_cst); // compile-time barrier |
13 | std::atomic_fetch_add_explicit(&a1, 1, std::memory_order_relaxed); |
14 | std::atomic_signal_fence(std::memory_order_seq_cst); |
(1) und (3) sind identisch und für Sigle-Core. (2) ist die Bullet-Proof Lsg auch für Multi-Core.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.