Forum: Mikrocontroller und Digitale Elektronik std:atomic auf STM32


von Gustav G. (gustavgggg)


Lesenswert?

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?

von Zino (zinn)


Lesenswert?

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.

von Gustav G. (gustavgggg)


Lesenswert?

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?

von Zino (zinn)


Lesenswert?

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().

von Wilhelm M. (wimalopaan)


Lesenswert?

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
von Hannes W. (hannes_w129)


Lesenswert?

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.

von Gustav G. (gustavgggg)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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
Noch kein Account? Hier anmelden.