Práce s vlákny v C

Re:Práce s vlákny v C
« Odpověď #60 kdy: 25. 01. 2021, 23:55:57 »
Mimochodem, v tom druhém odkazu je zásadní protiargument proti tomu navrženému řešení s (manuálním) deep copy:

private fields can't be accessed with reflection

Na to jsem si nevzpomněl. Showstopper.


Re:Práce s vlákny v C
« Odpověď #61 kdy: 25. 01. 2021, 23:57:20 »
Osobně jsem se základy práce s mutexy a podmínkovými proměnnými dočetl v tomto starodávném článku. Ten článek sice vyšel dávno před přechodem libpthread v Linuxu na NPTL, takže některé poznámky o interně používaných signálech apod. už neplatí - ale základní "o čem to je" platí myslím dál. Hrál jsem si s tou synchronizací v C a základním C++ postupně víc a víc, až jsem v jednom proprietárním prográmku měl asi 7 různých tříd objektů (které cosi obalovaly), každý měl svá 1-4 vlákna, mezi sebou si předávaly "práci" a pochopitelně se přitom všelijak zamykaly... jako houfec baletek. Fronta nebo obecně nějaká hromádka krmení, ochráněná podmínkovou proměnnou, je mocná zbraň :-) Není vůbec na škodu, myslet trochu "mimo předdefinované škatulky", a ze shůry daných základních synchronizačních primitiv si stavět složitější konstrukce na míru svému problému. Třeba více producentů pro jednoho konzumenta... podmínkovou proměnnou lze chránit prostou frontu, nebo třeba nějaký složitý key-value index s multikriteriální porovnávací funkcí... Jednalo se tehdy o nějakou komunikační gateway mezi více rozhraními, a dalo se to celé rozdrobit na datové objekty držené v indexech, které na sebe navzájem odkazovaly, kolem každého objektu tančilo několik vláken... jedním ze základních návrhových principů bylo, že každé vlákno smí delší dobu (až na neurčito) blokovat právě v jednom bodě, aby se zabránilo nepříjemnostem typu zbytečné vzájemné čekání nebo dokonce uváznutí. Tím jediným bodem mohla být podmínková proměnná (vlákno = konzument) nebo třeba čekání na vstup (událost) od fyzického I/O zařízení... Všimněte si, že při čekání na podmínkové proměnné je související mutex *odemčený*. Držet mutex dlouhodobě zamčený je hřích - přípustný pouze v případě, že to fakt nejde udělat rychleji nebo odložit na dobu, kdy zámek není potřeba (třeba když je zámkem chráněna manipulace s nějakým btree asociativním polem / indexem, byť u rozsáhlejšího btree může být třeba rebalancing procesorově a časově náročný).

BTW
Když si vezmete že jeden thread lockne resource, do toho mu kernel sebere kvantum, tak bude případný další thread viset než ho ten přerušený znova uvolní. Pro to co píšete to je jedno (desetiny sekundy za uherskej rok u příkladu na naučení se). Ale do budoucna je dobré mít pro lock/unlock makra a pak to časem udělat dobře (futexy pro linux, něco přenositelnějšího i jinam)

Možná tomu špatně rozumím, ale zrovna v tomhle případě mě držený zámek neuráží :-) Pokud má konkrétní vlákno zrovna práci na nějakém zamčeném "vzácném zdroji", třeba se delší dobu hrabe v nějakém indexu, a přeruší ho preemptivně scheduler, tak to vlákno prostě zůstane ve stavu "running". A pokud nějaká další vlákna trpělivě čekají na tentýž zámek, tak holt čekají dál a zcela po právu / smysluplně. Z pohledu scheduleru tato další vlákna "z vlastní vůle spí". Takže scheduler půjčí procesor na chvilku nějakému jinému procesu, který by také rád běžel. Halt zas chvilku někdo jiný tahá pilku. Nebo pokud se nikdo jiný o procesor nehlásí, dostane ho obratem zpátky naše původní vlákno, které se chce ještě chvilku hrabat v tom svém indexu - vlákno dostane procesor zpátky, protože je z pohledu scheduleru "running". Prostě: které vlákno má práci, a indikuje toto scheduleru, má šanci procesor dostat zpátky - a vlákna spící na podmínkových proměnných patrně spí dál zcela oprávněně, a při správném rozvržení dat a vláken je to jako celek dost slušně efektivní.

Mám na tuhle dobu a programátorské problémy hezké vzpomínky. Jak shluknout v kódu objekt (struct) a k němu náležející vlákna. Jak nastartovat vlákno a "memberizovat" ho, aby běželo jako metoda konkrétního objektu. Jak do toho objektu (třídy/structu) zakomponovat podmínkovou proměnnou a mutex, které si "vlastní" vlákna objektu budou zdvořile předávat. Jak to zamykání zabalit do "manipulačních" metod, aby další kód volající tyto metody nemusel řešit pthread primitiva. Jak z různých tříd takových "rozvlákněných objektů" skládat hierarchie / mesh topologie, a zároveň zajistit "graceful cleanup" při ukončení jednotlivého vlákna, případně kaskádovitý úklid vláken a objektů při ukončení programu... Nabízí se, zapojit do hry reference counting = osobně jsem přidával do "užitečných" objektů šablonový "invazivní" reference counting objekt, který tuším navíc obsahoval zámeček... aby ten reference counting fungoval z více vláken, a aby fungovalo "poslední zhasne" = po dekrementaci ref.counteru na nulu se objekt dále prostřednictvím zmíněného invazivního reference counteru sám destruuje... jde pouze o to zařídit, aby po dealokaci paměti
dobíhající member metoda už nesáhla do dat nyní již neexistujícího objektu :-) = dealokace dělat až těsně před návratem.

Podobně zábavné situace "slepice nebo vejce" nastávají při graceful shutdownu a řízenému zastavení všech vláken hlavní smyčkou programu, kterou přerušil signal handler apod. Resp. zařídit, aby došlo ke graceful shutdownu jak při zastavení vnějším povelem, tak při zastavení spontánním (vlákno zjistí chybu a proto se samo ukončí, případně to napřed nějak nahlásí).

Řekl bych, že tahle práce "bolí, ale hezky" :-) Ladit ty vejce a slepice je někdy záhul na mozkovnu. Ale je super, když to po vyladění celé chodí jak hodiny. A naopak není vůbec super, když to napíšete a odladíte na nějakém stroji/procesoru, pak to spustíte na jiném s troji s jiným počtem jader apod., a ono to začne padat, protože se změní "charakter konkurentního běhu více vláken" v těsném okolí zamykaných kritických sekcí :-) Je to *hodně* náročné na předvídavost a pečlivost při psaní kódu. A je to potenciálně veliká zábava.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Práce s vlákny v C
« Odpověď #62 kdy: 26. 01. 2021, 00:33:34 »
private fields can't be accessed with reflection
Tahle diskuse mě přestala bavit, jako obvykle vyletěla z věcných kolejí. Pravda je, že Go to neumí zajistit v době překladu, a u cizího kódu není garantováno v podstatě nic. V takové situaci, kdybych chtěl mít stoprocentní jistotu, bych si prostě zkopíroval relevantní pole z "neznámého" objektu do pomocného, který bych si nadefinoval sám ve svém kódu, abych měl zajištěno, že mi na něj nebude nikdo nijak šahat po tom, co ho pošlu kanálem, ať už kopií nebo jen ukazatel na něj, to je fuk. I výkonostně to je ostatně podstatně efektivnější než reflexe. Ovšem úplně nejlepší řešení by bylo použít Rust nebo ten Erlang :)

Re:Práce s vlákny v C
« Odpověď #63 kdy: 26. 01. 2021, 00:38:53 »
bych si prostě zkopíroval relevantní pole z "neznámého" objektu do pomocného
Což právě ten příspěvek, na kterej reaguješ, konstatuje, že nejde  ::)

To není vypadnutí z věcné koleje, to je totální neschopnost naslouchat argumentům, vyhodnocovat je a reagovat na ně.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Práce s vlákny v C
« Odpověď #64 kdy: 26. 01. 2021, 00:56:20 »
bych si prostě zkopíroval relevantní pole z "neznámého" objektu do pomocného
Což právě ten příspěvek, na kterej reaguješ, konstatuje, že nejde
Je to marný, je to marný, je to marný  :-\


Re:Práce s vlákny v C
« Odpověď #65 kdy: 26. 01. 2021, 07:24:21 »
Je to marný, je to marný, je to marný  :-\
Jo, je to marný, když neposloucháš. Jak chceš něco vykopírovávat ze struktury tohodle typu? https://godoc.org/go.uber.org/zap#Logger

Re:Práce s vlákny v C
« Odpověď #66 kdy: 26. 01. 2021, 08:45:41 »
Je to marný, je to marný, je to marný  :-\
Jo, je to marný, když neposloucháš. Jak chceš něco vykopírovávat ze struktury tohodle typu? https://godoc.org/go.uber.org/zap#Logger

Posilat channelem do gorutiny ruzne instance loggeru je neotrela myslenka.

Apropos, kdyz tu byla rec o Rustu a porovnani s GO, v Rustu jsou plnotucne thready s celym overheadem okolo, tedy defacto guvod, proc vxniko GO a vsecky node.js async mrdky.

Re:Práce s vlákny v C
« Odpověď #67 kdy: 26. 01. 2021, 09:25:28 »
Posilat channelem do gorutiny ruzne instance loggeru je neotrela myslenka.
Ježkovanoho, to je příklad. Jde o princip, ne o tuhle konkrétní věc. Nedokumentované struktury jsou všude možně, je to běžný pattern.

Apropos, kdyz tu byla rec o Rustu a porovnani s GO, v Rustu jsou plnotucne thready s celym overheadem okolo, tedy defacto guvod, proc vxniko GO a vsecky node.js async mrdky.
To už pár let není jediné možnost, AFAIK.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Práce s vlákny v C
« Odpověď #68 kdy: 26. 01. 2021, 09:53:15 »
Je to marný, je to marný, je to marný  :-\
Jo, je to marný, když neposloucháš. Jak chceš něco vykopírovávat ze struktury tohodle typu? https://godoc.org/go.uber.org/zap#Logger

Posilat channelem do gorutiny ruzne instance loggeru je neotrela myslenka.

Apropos, kdyz tu byla rec o Rustu a porovnani s GO, v Rustu jsou plnotucne thready s celym overheadem okolo, tedy defacto guvod, proc vxniko GO a vsecky node.js async mrdky.
Volba slova “neotřelá” je velmi ohleduplná k tomu, kdo ten nesmysl o posílání loggeru vyřknul :)

Rust nepoužívám a nijak podrobně neznám, ale co jsem tak postřehl, dostal teď async/await, takže nejspíš dostává kooperativní korutiny (jako C#, C++(20) nebo to Go).

Edit: https://www.i-programmer.info/news/98-languages/14282-asysnchronous-runtime-for-rust-released.html
« Poslední změna: 26. 01. 2021, 09:57:26 od Idris »

Re:Práce s vlákny v C
« Odpověď #69 kdy: 26. 01. 2021, 10:16:28 »
Volba slova “neotřelá” je velmi ohleduplná k tomu, kdo ten nesmysl o posílání loggeru vyřknul :)
Za prve: Kterou cast prispevku
Ježkovanoho, to je příklad. Jde o princip, ne o tuhle konkrétní věc. Nedokumentované struktury jsou všude možně, je to běžný pattern.
jsi nepochopil?

Za druhe: ne, neni to nijak zvlast neotrele. Pouzil jsem to jako priklad, protoze presne tohle mam v kodu pred sebou. Jsou tam nejake "objekty" (implementovane samozrejme strukturou), u kterych se nekde na zacatku kodu inicializuje logger. Ten se pak vlozi do struktury, aby si kazdy "objekt" mohl logovat tak, jak bylo na zacatku nastaveno.

Co je na tom "neotreleho"? A co je tak skandalniho na myslence, ze bych si chtel tenhle objekt nekam poslat channelem?

A vubec nejzasadnejsi otazka: proc tak urputne obhajujes neco, co zjevne ma svoje mouchy? Proc nemuzes proste priznat "jo, neni to idealni, slo by to udelat lip"? Ses ted jako placenej ambassador Go nebo jak?! Nechapu to. Pripominas mi javascriptare, kteri urputne obhajuji, jak je == v JS uplne v pohode a nema zadny problem.

 ::)

Re:Práce s vlákny v C
« Odpověď #70 kdy: 26. 01. 2021, 10:33:20 »
Osobně jsem se základy práce s mutexy a podmínkovými proměnnými dočetl v tomto starodávném článku. Ten článek sice vyšel dávno před přechodem libpthread v Linuxu na NPTL, takže některé poznámky o interně používaných signálech apod. už neplatí - ale základní "o čem to je" platí myslím dál.

Ještě jsem si vzpomněl, že jsem možná první zmínku o libpthread a vláknech četl v papírovém vydání "Linux - začínáme programovat", někdy v roce 2000. A jak jsem při následném online studiu užasl, že v té knížce úplně vynechali podmínkové proměnné (conditional variables). A teď vidím online 4.vydání v PDF, a v kapitole 12 dodnes není ani zmínka o podmínkových proměnných :-) Ostuda. Listuju v papírové knížce a našel jsem jako záložku svůj papír, kde jsem si průchod dvou vláken "synchronizací s podmínkovou proměnnou" načmáral :-) A vytištěnou stránku z Linux Standards Base reference, která obsahuje seznam funkcí libpthread.

Re:Práce s vlákny v C
« Odpověď #71 kdy: 26. 01. 2021, 10:48:18 »
Osobně jsem se základy práce s mutexy a podmínkovými proměnnými dočetl v tomto starodávném článku. Ten článek sice vyšel dávno před přechodem libpthread v Linuxu na NPTL, takže některé poznámky o interně používaných signálech apod. už neplatí - ale základní "o čem to je" platí myslím dál.

Ještě jsem si vzpomněl, že jsem možná první zmínku o libpthread a vláknech četl v papírovém vydání "Linux - začínáme programovat", někdy v roce 2000. A jak jsem při následném online studiu užasl, že v té knížce úplně vynechali podmínkové proměnné (conditional variables). A teď vidím online 4.vydání v PDF, a v kapitole 12 dodnes není ani zmínka o podmínkových proměnných :-) Ostuda. Listuju v papírové knížce a našel jsem jako záložku svůj papír, kde jsem si průchod dvou vláken "synchronizací s podmínkovou proměnnou" načmáral :-) A vytištěnou stránku z Linux Standards Base reference, která obsahuje seznam funkcí libpthread.

Klasické synchronizační vzory jsou výborně popsány ve free knize Little Book of Semaphores: https://greenteapress.com/wp/semaphores/ . Vždy jsem tam našel co jsem potřeboval.

Re:Práce s vlákny v C
« Odpověď #72 kdy: 26. 01. 2021, 10:52:09 »
Volba slova “neotřelá” je velmi ohleduplná k tomu, kdo ten nesmysl o posílání loggeru vyřknul :)
Za prve: Kterou cast prispevku
Ježkovanoho, to je příklad. Jde o princip, ne o tuhle konkrétní věc. Nedokumentované struktury jsou všude možně, je to běžný pattern.
jsi nepochopil?

Za druhe: ne, neni to nijak zvlast neotrele. Pouzil jsem to jako priklad, protoze presne tohle mam v kodu pred sebou. Jsou tam nejake "objekty" (implementovane samozrejme strukturou), u kterych se nekde na zacatku kodu inicializuje logger. Ten se pak vlozi do struktury, aby si kazdy "objekt" mohl logovat tak, jak bylo na zacatku nastaveno.

Co je na tom "neotreleho"? A co je tak skandalniho na myslence, ze bych si chtel tenhle objekt nekam poslat channelem?

A vubec nejzasadnejsi otazka: proc tak urputne obhajujes neco, co zjevne ma svoje mouchy? Proc nemuzes proste priznat "jo, neni to idealni, slo by to udelat lip"? Ses ted jako placenej ambassador Go nebo jak?! Nechapu to. Pripominas mi javascriptare, kteri urputne obhajuji, jak je == v JS uplne v pohode a nema zadny problem.

 ::)

Jsem překvapen, ale zcela souhlasím s Mirkem. Pokud je to aspoň trochu praktické, naprosto preferuju compile-time safety před runtime asserty, unit testy, štábní kulturou, selským rozumem a podobnými věci, na které je ošemetné se spoléhat. V tomto smyslu je určitě Rust nebo Elixir napřed před Go.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Práce s vlákny v C
« Odpověď #73 kdy: 26. 01. 2021, 11:15:21 »
Si to ještě jednou pozorně projdi, opakovaně jsem psal, že to v Go v době překladu nejde a že const/initonly by se šiklo. Jinak je mi Go celkem ukradené, když už, má mnohem horší WTF vlastnosti než posílání ukazatelů kanálama. Vzhledem k tomu, že tvoje příspěvky jsou čím dál tím slabomyslnější (nevím, proč tě baví trollení, ale to je fuk), dodrž, číms vyhrožoval (omez příspěvky na nula).

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Práce s vlákny v C
« Odpověď #74 kdy: 26. 01. 2021, 11:17:23 »
Pokud je to aspoň trochu praktické, naprosto preferuju compile-time safety před runtime asserty, unit testy, štábní kulturou, selským rozumem a podobnými věci, na které je ošemetné se spoléhat. V tomto smyslu je určitě Rust nebo Elixir napřed před Go.
Na tom se tu evidentně všichni shodneme.