RTOS dobra praksa

Vse o programiranju na in za PC

Moderatorji: Kroko, tilz0R

RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 07 Jul 2018, 00:05

Kadar pišete kakšno knjižnico, ki bi lahko bila uporabljena z ali brez RTOS, ali v takšnem primeri pišete thread-safe API in en API, ki ni thread-safe?

Recimo, da imam OneWire scan naprav operacijo, in ker hočem, da sem thread safe, bom z mutexom zaščitil API:

Spodnji primer zaklene dostop z mutexom, potem pa začne scan. V scanu je potrebno poslati reset pulse, pa potem ukaz za iskanje senzorja, etc.
Če je DS18B20 najdem, hočem takoj poslati 12-bitni način, kar pomeni ponovem reset pulse, etc.
Koda: Izberi vse
//Pseudo-koda

Mutex_lock();
start_search() //pošlji reset pulse na 1-wire
while ((rom_id = search_next()) > 0) {
    if is_ds18b20(rom_id))
        set_12-bit_resolution(rom_id);
}
Mutex_unlock();



Medtem sem pa tudi reset funkcijo naredil thread safe, ki zgleda nekako tako:

Koda: Izberi vse
reset(void) {
    Mutex_lock();
    send_reset_pulse();
    Mutex_unlock();
    return success();
}


Če sedaj malo pomislimo, je jasno, da ko je mutex že zaklenjen za search, je znotraj le-tega klic na reset pulse, ki tudi naredi mutex lock, kar ima lahko za posledico 2 stvari:
- Dead-Lock, če mutex ni rekurziven
- Normalno delovanje, če je mutex rekurziven.

Kakšna je vaša praksa glede tega? Uporabljate izključno rekurzivne mutexe, ali bi napisali v takšnem primeru 2 reset funkciji, ena, ki pričakuje, da je bil mutex zaklenjen nekje zunaj in ena, ki to naredi sama? Kaj, če je takšnih podobnih funkcij 100? Bi dodali vsaki funkciji parameter "lock_mutex"?

Edit: Govorim o izključno C-ju.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 07 Jul 2018, 00:29

V tem primeru bi uporabil "scoped lock".

Resource Acquisition is Instantiation
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 07 Jul 2018, 12:21

Kroko je napisal/-a:V tem primeru bi uporabil "scoped lock".

Resource Acquisition is Instantiation


Kako pa če smo v C-ju?
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 07 Jul 2018, 15:11

Potem je čas da začnete uporabljati kaj bolj sodobnega.
Da vas ne bo povozil čas in boste poznali samo muzejsko tehnologijo :-)

PS
Še Arduino je C++.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 07 Jul 2018, 15:49

Drugače bi pa v C to rešil z makri.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 07 Jul 2018, 19:31

Kroko je napisal/-a:Drugače bi pa v C to rešil z makri.

Kakšen primer?
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 07 Jul 2018, 20:29

Sem malce bolje razmislil. Iz enega threda sploh ne bi smelo biti potrebe po mutexu. Če potrebuješ rekurzivne mutexe potem zna biti nekaj narobe v designu.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 07 Jul 2018, 21:41

Kroko je napisal/-a:Iz enega threda sploh ne bi smelo biti potrebe po mutexu.

Tega ne razumem najbolje, kaj si hotel povedati?

Kroko je napisal/-a:Če potrebuješ rekurzivne mutexe potem zna biti nekaj narobe v designu.

S tem se ne strinjam. Če bi potreba po rekurzivnih mutex pomenila "slab design", potem jih noben RTOS ne bi imel
Spodaj je en primer, kjer lahko rekurzivni mutex reši težavo pisanja ogromno kode. Zanima pa me, kako to rešujete drugi.

Lep primer je LwIP knjižnica. Ločuje dvojne funkcije, ene ki jih lahko kličeš samo iz thread-a, druge, ki jih lahko kličeš samo iz callback-ov, ki so že pod mutex protekcijo in niso thread-safe.

Potem je pa tukaj kakšen GUI lib, kjer lahko velikosti widget skriješ iz main thread-a, recimo, ko pritisneš tipko (fizično tipko na boardu). Takrat rabiš mutex protekcijo, da slučajno še kakšen drug thread ne probava nastaviti GUI parametrov.
Imaš pa tudi situacijo, kjer se zgodi event, kadar si pritisnil na touch na zaslonu, da sporoči nazaj "zgodil se je click event". Ta klic je tudi že pod mutex protekcijo, ki ga je zaklenila v "gui_process" funkciji (ali podobni, tisti ki preverja če je kaj za narediti). Recimo, da hočem tukaj tudi skriti widget. Kličem funkcijo, ki sama zaklene mutex. Ker je že zaklenjen od prej, bom (ob neuporabi rekurzivnega mutexa) prišel v dead-lock.

Lahko pa rešim to tako, da naredim thread-safe API funkcije, in funkcije, ki jih lahko kličeš samo iz callback-ov. To pomeni dvojno delo saj lahko v main-threadu počneš iste stvari kot v callbacku.

Opcija pa je tudi, da so vse API funkcije "univerzalne" in imajo "protect" parameter. Če je nastavljen na 1, potem funkcija zaklene mutex, drugače ga ne. V tem primeru je potrebno funkcijo iz callbacka klicati z protect = 0, drugače protect = 1.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 07 Jul 2018, 22:25

Uf, saj si si skoraj sam odgovoril. Imaš "interne" funkcije brez mutexov in "interface" funkcije, ki mutex uporabljajo. Za te "inerface" funkcije (pogosto jih naredim kar inline) naj rekurzivni mutex ne bi bil potreben. Brez RTOS pa naj bodo makri na mutex lock prazni. Optimizer naredi ostalo.

Čeprav ti je ideja mrzka se začni spoprijateljevati z C++. Ne bi bilo prav, da bi dober programer, kot si ti, zastal v razvoju.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 07 Jul 2018, 23:04

Kroko je napisal/-a:Uf, saj si si skoraj sam odgovoril. Imaš "interne" funkcije brez mutexov in "interface" funkcije, ki mutex uporabljajo. Za te "inerface" funkcije (pogosto jih naredim kar inline) naj rekurzivni mutex ne bi bil potreben. Brez RTOS pa naj bodo makri na mutex lock prazni. Optimizer naredi ostalo.


Ja, trenutno imam tako pri GUI knjižnici, ki skupaj nanese en kup enih funkcij.

Kroko je napisal/-a:Čeprav ti je ideja mrzka se začni spoprijateljevati z C++. Ne bi bilo prav, da bi dober programer, kot si ti, zastal v razvoju.

Sem kar dober prijatelj z njim, ga redno uporabljam pri PC aplikacijah in pri embedded privatnih. Kar dajem na splet, pišem v C, o tem zakaj, sem že večkrat povedal.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 08 Jul 2018, 00:10

Porem pa vse ok, čeprav se nekako ne spomnim, kaj si povedal.

Kode morda res izgleda veliko vendar se je prevede bolj malo. Take stvari bolj "bolijo" dokler kodo še pišeš/debugiraš. Kasneje se to hitro pozabi.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 08 Jul 2018, 00:12

Kroko je napisal/-a:Porem pa vse ok, čeprav se nekako ne spomnim, kaj si povedal.

Koda v Cju, dela na C++, kontra pač ne.

Kroko je napisal/-a:Kode morda res izgleda veliko vendar se je prevede bolj malo. Take stvari bolj "bolijo" dokler kodo še pišeš/debugiraš. Kasneje se to hitro pozabi.

Brez dvoma, kompiler je pameten te dni.

Vglavnem uporabljam C++ za kakšne wrapperje C funkcij, da potem API layer poteka lažje.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 29 Jul 2018, 00:45

Nič, odločil sem se, da vsaki API funkciji podam parameter "const uint8_t protect", ki ga potem user na API layerju nastavi ali hoče protekcijo ali ne.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 29 Jul 2018, 18:03

Nastavljanje zaščite ni stvar userja. Jaz bi raje naredil dve metodi. Interno brez zaščite in api, ki kliče interno.
Koda: Izberi vse
void resetInt()
{
  ...
}

void reset()
{
  LOCK();
  resetInt();
  UNLOCK();
}

void searchInt()
{
  resetInt();
  ...
}

void search()
{
  LOCK();
  searchInt();
  UNLOCK();
}


LOCK in UNLOCK so macri.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 29 Jul 2018, 22:18

Mora pa vedeti ali kliče interno ali ne. Ni isto? :)
Pa še na stacku prišparaš če ma metoda parametre.

Samo razmišljam na glas.

Edit: Da še razložim.
Pri meni se lahko API funkcije kličejo iz thread-ov (protekcija potrebna) ali pa iz callback-a. Callback se kliče, ko je protekcija vključena, tako, da če user spet kliče "public API", bo hotel mutex ponovno zakleniti. To pomeni eno izmed:

- Dead lock, če mutex ni rekurziven
- Uporaba recursive mutexov (generalno gledano slabo, včasih je to najlažji način, code execution je počasnejši, sploh če je veliko API klicev potrebnih)
- Imeti dvojne funkcije, ene, ki se kličejo iz callbacka (private, protekcija ni potrebna), druge ki se iz thread-a (protekcija potrebna). V tem primeru mora user vedeti ali hoče protekcijo ali ne. Odločil sem se za eno funkcijo, ki ima parameter za protekcijo.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 01:37

Ni isto. Če interno vedno kličeš interno, preko pija pa zunanje funkcije. Če lock ni potreben potem so macri prazni. Ostalo naredi optimizer.
V tvojem primeru imaš celo problem saj koda ni nonstop zaščitena.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 04:52

"Macri prazni" je nekaj kar je compile time.
Potem moram vedeti katero funkcijo klicati, ali tisto ki omogoča protekcijo, ali tisto ki jo ne.

Interno vedno klicem funkcije z lock = 0.

Zakaj bi bilo to problematično? Zakaj koda ni vedni zaščitena?

Popoldan dam example.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a S53DZ » 30 Jul 2018, 08:11

Tole vajino konstruktivno prerekanje se mi zdi kar zanimivo, ampak pri rabi toliko slengov, anglizmov (morda so kakšni celo nujni!?) vaju želim opozoriti eno bistveno napako namreč, da je prevajanje: "protection" v protekcija nepovratno.
Namreč, protekcija se prevaja v "favouritism", kar je tudi razumevanje v slovenskem jeziku in nikakor ni "protection".

Torej, svetujem previdnost, da ne spremenita vsebine. Ha.
Za vse nas, ki beremo za vama. In za zanamce. Nisem purist, ampak nezavedna sprememba vsebine? Ja, to me pa moti.

PS:
Je rekel: "Zdaj grem pa vokat psa" in to ni pomenilo, da ga bo dal v vok.
Uporabniški avatar
S53DZ
 
Prispevkov: 1148
Pridružen: 18 Jan 2015, 10:58
Kraj: Ljubljana
Zahvalil se je: 200 krat
Prejel zahvalo: 385 krat
Uporabnika povabil: S52O
Število neizkoriščenih povabil: 41

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 08:24

tilz0R je napisal/-a:"Macri prazni" je nekaj kar je compile time.

Saj pred prevajanjem veš, ali uporabljaš RTOS ali ne.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 08:42

S53DZ je napisal/-a:Tole vajino konstruktivno prerekanje se mi zdi kar zanimivo, ampak pri rabi toliko slengov, anglizmov (morda so kakšni celo nujni!?) vaju želim opozoriti eno bistveno napako namreč, da je prevajanje: "protection" v protekcija nepovratno.
Namreč, protekcija se prevaja v "favouritism", kar je tudi razumevanje v slovenskem jeziku in nikakor ni "protection".

Torej, svetujem previdnost, da ne spremenita vsebine. Ha.
Za vse nas, ki beremo za vama. In za zanamce. Nisem purist, ampak nezavedna sprememba vsebine? Ja, to me pa moti.

PS:
Je rekel: "Zdaj grem pa vokat psa" in to ni pomenilo, da ga bo dal v vok.


Mogoče jih je res veliko :)
Protection = mutex_lock, tako da le en thread dela z resourcem naenkrat.

Po moje pa to ni kreganje.

tilz0R je napisal/-a:Če smo vsi takoj mnenja da je neka stvar dobra ideja, potem to zagotovo ni dobra ideja. Če je nekdo, ki je proti, je to znak, da se bo treba vsesti, pogledati prednosti/slabosti in potem odločiti kako naprej.

Mislim, da bi si takšne debate lahko marsikdo na tem forumu pogledal, namesto neumnosti, ki se dogajajo na forumu :)

Pripravil sem 2 primera, enega na način, kot sem razumel Krokota, drugega na način, kot sem pri sebi implementiral.
Pognati se da obe kodi na spodnjih povezavah v spletnem prevajalniku.

Kroko izvedba: https://repl.it/@TilenMajerle/RTOSKroko
tilz0R izvedba: https://repl.it/@TilenMajerle/RTOStilz0R

Pri Krokotu vidim sledeče:
- Prednost, ker vsaka funkcija nima "protect" parametra in je ločeno z "_int" suffix-om
- Slabost, ker ima vsaka funkcija še protected API, če se zamenja API eni, se mora tudi drugi, kar lahko vodi v kakšen bug (primer: funkcija sprejme argumente istih tipov, a jim zamenjamo vrstni red, compiler ne bo jokal).

Pri tilz0R vidim sledeče:
- Prednost, ker je single funkcija za oboje
- Potencialna slabost, ker ima vsaka funkcija "protect" parameter, ki dodatno zajema stack. Kadar ima funkcija vsaj en parameter, smo vsaj na istem (ali boljšem) kot pri Kroko izvedbi, saj pri Kroko izvedbi funkcija kliče funkcijo z istimi parametri = 2x function call + 2x push/pop stack-a.

Pri obeh vidim sledeče:
- Programer mora vedeti, ali hoče funkcijo, ki zaklene mutex ali tisto, ko je mutex že zaklenjen.
- Tega se je dobro zavedati, če pišeš API na RTOS ali tudi na non-RTOS sistemu

Rezultat obeh programov je pa isti. Najprej 3x kličem api funkcijo "iz drugega thread-a", potem pa kličem api_process, ki zaklene mutex in kliče callback. V callback-u zato ni potrebno uporabljati API funkcij, ki zaklenejo mutex ponovno.

Tisti, ki se misli vmešavati v temo, prosim konstruktivna mnenja in ne "krneki".
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 10:44

tilz0R je napisal/-a:... saj pri Kroko izvedbi funkcija kliče funkcijo z istimi parametri = 2x function call + 2x push/pop stack-a.


Hmm, ker si človek delaš napako kakršno dela večina ljudi.

Ko vidiš tole kodo:
Koda: Izberi vse
int data = 0;
bool locked = false;

void lock()
{
    locked = true;
}

void unlock()
{
    locked = false;
}

void api_int()
{
  data++;
}

void api()
{
    lock();
    api_int();
    unlock();
}

int main()
{
  api();
}


vidiš tale asembler:

Koda: Izberi vse
data:
        .zero   4
locked:
        .zero   1
lock():
        push    rbp
        mov     rbp, rsp
        mov     BYTE PTR locked[rip], 1
        nop
        pop     rbp
        ret
unlock():
        push    rbp
        mov     rbp, rsp
        mov     BYTE PTR locked[rip], 0
        nop
        pop     rbp
        ret
api_int():
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR data[rip]
        add     eax, 1
        mov     DWORD PTR data[rip], eax
        nop
        pop     rbp
        ret
api():
        push    rbp
        mov     rbp, rsp
        call    lock()
        call    api_int()
        call    unlock()
        nop
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        call    api()
        mov     eax, 0
        pop     rbp
        ret


računalniki niso ljudje in v resnici naredijo drugače:

Koda: Izberi vse
lock():
        mov     BYTE PTR locked[rip], 1
        ret
unlock():
        mov     BYTE PTR locked[rip], 0
        ret
api_int():
        add     DWORD PTR data[rip], 1
        ret
api():
        add     DWORD PTR data[rip], 1
        mov     BYTE PTR locked[rip], 0
        ret
main:
        add     DWORD PTR data[rip], 1
        xor     eax, eax
        mov     BYTE PTR locked[rip], 0
        ret


kakor vidiš ni nobenih callov, pushov in popov.


Še tvoj primer:
Koda: Izberi vse
int data = 0;
bool locked = false;

void lock(bool protect)
{
    if (protect)
        locked = true;
}

void unlock(bool protect)
{
    if (protect)
        locked = false;
}

void api(bool protect)
{
    lock(protect);
    data++;
    unlock(protect);
}

int main()
{
  api(true);
}


Ki pa se prevede takole:
Koda: Izberi vse
lock(bool):
        test    dil, dil
        je      .L1
        mov     BYTE PTR locked[rip], 1
.L1:
        ret
unlock(bool):
        test    dil, dil
        je      .L4
        mov     BYTE PTR locked[rip], 0
.L4:
        ret
api(bool):
        mov     eax, DWORD PTR data[rip]
        add     eax, 1
        mov     DWORD PTR data[rip], eax
        test    dil, dil
        je      .L7
        mov     BYTE PTR locked[rip], 0
        ret
.L7:
        ret
main:
        add     DWORD PTR data[rip], 1
        xor     eax, eax
        mov     BYTE PTR locked[rip], 0
        ret
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 10:49

Good catch. Dober compiler bo to naredil kot si omenil.
Zanimivo bi bilo videti kakšen embedded primer, kadar lock ni le "locked = true", pač pa operating system zadeva, čemur je lock namenjen.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 11:02

No problem

"tvoja" koda:
Koda: Izberi vse
#include <mutex>

int data = 0;
std::mutex mtx;

void lock(bool protect)
{
    if (protect)
        mtx.lock();
}

void unlock(bool protect)
{
    if (protect)
        mtx.unlock();
}

void api(bool protect)
{
    lock(protect);
    data++;
    unlock(protect);
}

int main()
{
  api(true);
}


Koda: Izberi vse
lock(bool):
        mov     eax, OFFSET FLAT:_ZL28__gthrw___pthread_key_createPjPFvPvE
        test    rax, rax
        je      .L11
        test    dil, dil
        jne     .L15
.L11:
        ret
.L15:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:mtx
        call    __gthrw_pthread_mutex_lock(pthread_mutex_t*)
        test    eax, eax
        jne     .L16
        add     rsp, 8
        ret
.L16:
        mov     edi, eax
        call    std::__throw_system_error(int)
unlock(bool):
        mov     eax, OFFSET FLAT:_ZL28__gthrw___pthread_key_createPjPFvPvE
        test    rax, rax
        je      .L17
        test    dil, dil
        je      .L17
        mov     edi, OFFSET FLAT:mtx
        jmp     __gthrw_pthread_mutex_unlock(pthread_mutex_t*)
.L17:
        ret
api(bool):
        test    dil, dil
        jne     .L40
        add     DWORD PTR data[rip], 1
        ret
.L40:
        push    rbx
        mov     ebx, OFFSET FLAT:_ZL28__gthrw___pthread_key_createPjPFvPvE
        test    rbx, rbx
        je      .L27
        mov     edi, OFFSET FLAT:mtx
        call    __gthrw_pthread_mutex_lock(pthread_mutex_t*)
        test    eax, eax
        jne     .L41
.L27:
        add     DWORD PTR data[rip], 1
        test    rbx, rbx
        je      .L42
        mov     edi, OFFSET FLAT:mtx
        pop     rbx
        jmp     __gthrw_pthread_mutex_unlock(pthread_mutex_t*)
.L42:
        pop     rbx
        ret
.L41:
        mov     edi, eax
        call    std::__throw_system_error(int)
main:
        push    rbx
        mov     ebx, OFFSET FLAT:_ZL28__gthrw___pthread_key_createPjPFvPvE
        test    rbx, rbx
        je      .L44
        mov     edi, OFFSET FLAT:mtx
        call    __gthrw_pthread_mutex_lock(pthread_mutex_t*)
        test    eax, eax
        jne     .L56
.L44:
        add     DWORD PTR data[rip], 1
        test    rbx, rbx
        je      .L45
        mov     edi, OFFSET FLAT:mtx
        call    __gthrw_pthread_mutex_unlock(pthread_mutex_t*)
.L45:
        xor     eax, eax
        pop     rbx
        ret
.L56:
        mov     edi, eax
        call    std::__throw_system_error(int)
mtx:
        .zero   40
data:
        .zero   4



"moja koda"

Koda: Izberi vse
#include <mutex>

int data = 0;
std::mutex mtx;

void api_int()
{
    data++;
}

void api()
{
    mtx.lock();
    data++;
    mtx.unlock();
}

int main()
{
  api();
}


Koda: Izberi vse
api_int():
        add     DWORD PTR data[rip], 1
        ret
api():
        push    rbx
        mov     ebx, OFFSET FLAT:_ZL28__gthrw___pthread_key_createPjPFvPvE
        test    rbx, rbx
        je      .L4
        mov     edi, OFFSET FLAT:mtx
        call    __gthrw_pthread_mutex_lock(pthread_mutex_t*)
        test    eax, eax
        jne     .L13
.L4:
        add     DWORD PTR data[rip], 1
        test    rbx, rbx
        je      .L3
        mov     edi, OFFSET FLAT:mtx
        pop     rbx
        jmp     __gthrw_pthread_mutex_unlock(pthread_mutex_t*)
.L3:
        pop     rbx
        ret
.L13:
        mov     edi, eax
        call    std::__throw_system_error(int)
main:
        sub     rsp, 8
        call    api()
        xor     eax, eax
        add     rsp, 8
        ret
mtx:
        .zero   40
data:
        .zero   4


Pripisal bi še to, da je taka uporaba mutexa dobra samo za ta primer, ne pa za resen program. O temu bom pisal v nadaljevanju mojih C++ blodenj.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 11:28

Razlika med klici je očitna, vsaj na WIN32.
Zgleda, da bom naredil tako, da bodo vse funkcije brez implementacije lock-ov, potem pa naj user sam kliče lock pred klicem funkcije, oz. uporabi macro:

Koda: Izberi vse
lock();
api(); //Funkcija ne implementira locka
unlock();


Ali, če je to preveč dela za programerja, potem lahko:

Koda: Izberi vse
#define LOCKED(call)      do { lock(); call; unlock(); } while (0)

LOCKED(api());   //Kliči API z lock parametrom


Imam gladko več kot 200 API funkcij in ne mislim delat dvojnih verzij, ker to je strel v glavo :D
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 11:32

To je na prvi uč dobra ideja. Ampak samo na prvi uč. Se skriva past.

Koda: Izberi vse
int data = 0;
void api()
{
  data++;
  for(int i=0; i<10000; i++)
  {
    //do something that does not need protection
  }
}

void main()
{
  for(int i=0; i<10000; i++)
  {
    LOCK();
    api();
    UNLOCK();
  }
}
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 11:33

V mainu daš lock pred for zanko.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 11:35

Namesto _int jaz uporabljam _raw postfix - je bolj enostavno ko kaj iščeš.
Interne metode velikokrat sploh ne rabijo biti v header datoteki saj se kličejo samo interno.

Če malo reorganiziraš bo tudi bolj čitljivo. V priponkah primer
Priponke
api_c.txt
(998 bajtov) Prenešeno 5 krat
api_h.txt
(1.29 KiB) Prenešeno 5 krat
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 11:36

tilz0R je napisal/-a:V mainu daš lock pred for zanko.

Potrem bo pa vse za vedno zaklenjeno in ostali threadi sploh ne bodo mogli dostopati do apija.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 11:37

Bodo počakali N sekund, da se atomska operacija konča :D
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 11:41

Ampak čakali bodo tudi takrat, ko jim ni treba.
Če želiš, da je knjižnica thread safe, potem mora implementirati ustrezne varovalke.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 11:45

Kroko je napisal/-a:Ampak čakali bodo tudi takrat, ko jim ni treba.
Če želiš, da je knjižnica thread safe, potem mora implementirati ustrezne varovalke.


Načeloma, ko naredim knjižnico takšnega tipa, se mora vsaka API funkcija končati, preden se nova lahko začne. Tako, da v tem primeru nimam situacije, ko bi čakal kakšen event pri katerem bi moral izklopiti lock znotraj knjižnice.

Takšno situacijo, ki jo omenjaš, imam pri ESP8266 AT knjižnici. Tam recimo resource čaka, da pridejo podatki "od zunaj". Medtem ko čaka sprostiš protekcijo in čakaš nek semafor. Medtem API lahko dela drugi, imaš pa spremenljivke (varovalke), ki ustrezno povejo, kaj lahko drugi delajo ta čas, ko glavnina čaka nek event.

Ali sem te pravilno razumel?
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 11:57

Recimo da si.
Če je v tvojem primeru to "implementacijski detail" potem ok, ni pa to dobra praksa.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 11:59

Kroko je napisal/-a:Recimo da si.
Če je v tvojem primeru to "implementacijski detail" potem ok, ni pa to dobra praksa.


Ne štekam. Prosim razloži. Dodaj še prosim primer, kjer bi moral znotraj API-ja prekiniti lock in dovoliti drugemu resource-u, da ga bom 100% razumel.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: RTOS dobra praksa

OdgovorNapisal/-a Kroko » 30 Jul 2018, 12:51

Tole je 10 threadov brez sinhronizacije:
http://coliru.stacked-crooked.com/a/4aa2c51d806039ab
Se vidi, da vse dela narobe zato malo zaklenemo.

Najprej kar vse.
http://coliru.stacked-crooked.com/a/a39d0ebfa0d757d8
Online prevajalnik doživi timeout saj traja predolgo.

Sedaj zaklenemo samo nujne stvari.
http://coliru.stacked-crooked.com/a/ae004442c6442133
Dela!

Še koda za arhiv:
Koda: Izberi vse
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <chrono>

std::mutex _Mtx;

void SomethingStupid()
{
   int result = 0;
   for (int i = 0; i < 1000000000; i++)
   {
      result += i;
   }

   _Mtx.lock();
   std::cout << "Sum of all those numbers is ...";
   std::this_thread::sleep_for(std::chrono::milliseconds(500));
   std::cout << " wait for it ...";
   std::this_thread::sleep_for(std::chrono::milliseconds(500));
   std::cout << " " << result << std::endl;
   _Mtx.unlock();
}

int main()
{
   std::cout << "Welcome My Son, Welcome To The Machine" << std::endl;

   auto start = std::chrono::system_clock::now();

   std::vector<std::thread> pool;
   for (int i = 0; i < 10; i++)
   {
      pool.push_back(std::thread(SomethingStupid));
   }

   for (int i = 0; i < 10; i++)
   {
      if (pool[i].joinable())
         pool[i].join();
   }

   auto end = std::chrono::system_clock::now();
   auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
   std::cout << "Elapsed time: " << elapsed.count() << "ms" << std::endl;

   std::this_thread::sleep_for(std::chrono::milliseconds(100));
   std::cout << "This Is The End, My Only Friend, The End" << std::endl;
   std::cin.get();
   return 0;
}


Priponke
Cpp.zip
(3.55 KiB) Prenešeno 3 krat
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4079
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 617 krat
Prejel zahvalo: 1314 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 242

Re: RTOS dobra praksa

OdgovorNapisal/-a tilz0R » 30 Jul 2018, 12:56

Ok potem se pravilno razumel. Ti pač čakaš sleep (oz. OS implementira nek sleep), jaz pa pri ESP8266 AT lib nek semafor.

Takšen način je pač library implementation pomemben. Recimo FATFS knjižnica česa takšnega ne potrebuje. Kakšen AT driver pač potrebuje, etc.

Tema se lahko zaključi na tej točki :)
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1476
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 190 krat
Prejel zahvalo: 362 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255


Vrni se na Programski jeziki

Kdo je na strani

Po forumu brska: 0 registriranih uporabnikov in 1 gost