Egyszerű, multiplatform UI toolkit

Fórumok

Kerestem egy egyszerűen használható UI toolkit-et ANSI C-ben, és a Nuklear-t találtam (a C++ megfelelője az ImGui, de az nem használható ANSI C-ből).

Nem tudom, hányan ismeritek ezeket, de én nagyon felhúztam magam rajtuk, csupa hazugság a Nuklear. Állítólag kicsi (hát rohadtul nem, a 18000 SLoC az nagyon nem kevés), állítólag hatékony (hát rohadtul nem, folyamatosan memóriát allokálgat és minden képkockánál kovertálgatni kell OpenGL esetén), és állítólag könnyen integrálható (hát rohadtul nem, gyakorlatilag minden glue kódot a nulláról magadnak kell megírni). Ja, és ez az immediate-mode konkrétan egy használhatatlan koncepció, multithreading esélytelen vele például. Ja, és még egy: kurvára nem is C89-ben íródott, hazudik a a README-je...

Szóval, hogy rövidre fogjam, csináltam egy UI toolkitet, ami valóban tudja mindazt, amit a Nuklear igér, de képtelen teljesíteni.
SMGUI

- Státusz-Módú GUI (nem immediate-mode és nem is callback-driven, csak hivatkozni kell a már meglévő változóidra és kész)
- egyaránt használható ANSI C és C++ forrásokból is
- Egyetlen, függőségmentes fejlécfájl (plusz opcionális modulok)
- Platform és backend független (a repóban GLFW3, SDL2/3 és X11 illesztő modulok találhatók, ezek tartalmazzák a glue kódot)
- Bármilyen fontot képes kezelni (a repóban PC Screen Font (amit a Linux Console használ) és vektor fontokhoz SSFN modul található)
- Kis kódbázis (tényleg, mindössze kb. 2500 SLoC)
- Kevés memóriát eszik (gyakorlatilag csak ablak átméretezésnél allokál memóriát, képernyő méretűt és ennyi)
- Könnyen integrálható (kb. 5 sornyi kóddal)
- HTML flow-szerű, flexibilis elrendezés
- Bővíthető a kódodból új widgetekkel (példának egy On-Screen Keyboard-os szövegbeviteli mező van a repóban)
- UTF-8 és többnyelvűség támogatás (a nyelv akár menet közben is változtatható)
- teljes UNICODE támogatás (ami a Nuklear font bakerével képtelenség, túl sok az a 0x10FFFF darab glif egyetlen textúrához)
- multithreading támogatás (ami immediate-mode esetén képtelenség)
- természetesen magyar nyelvű doksival: https://bztsrc.gitlab.io/smgui/index.hu.html

A licensze MIT, szóval szabadon beépíthető akár fizetős alkalmazásokba is.

Hozzászólások

szép!

4 és fél éve csak vim-et használok. elsősorban azért, mert még nem jöttem rá, hogy kell kilépni belőle.

Köszönöm a lelkesítő hozzászólásokat! Dobjatok pár csillagot a repóra, ha tetszik :-) Előre is kösz!

Újdonságok:
- teljesképernyős mód (ui_fullscreen(), felbontásváltás nélkül)
- összes gamepad gomb elérhető immár
- X11 alatt volt egy kis pitty-putty a copy'n'paste-el, ez javítva
- GLFW kódtiszogatás, kikerült a GLES mert felesleges volt

Érkezik:
- jobb OSK integrálás
- platformfüggetlen fájlböngésző mező

- platformfüggetlen fájlböngésző mező

Ha ebből tudnál filepickert csinálni, az nagyon faintos lenne, simán használnám. Ez nekem nagy vesszőparipám, hogy jelenleg csak a Gtk és Qt filepicker az, ami általánosan támogatott a legtöbb szoftverben, meg mindenféle portálos gányolás kell hozzá, sajátot meg nem lehet használni. Ez egy rákfenéje a Linuxnak, szarok a filepicker megoldások, bugosak, bloatok, nincs belőlük nagy választék.

The world runs on Excel spreadsheets. (Dylan Beattie)

Ha ebből tudnál filepickert csinálni, az nagyon faintos lenne, simán használnám.

Pontosan erre gondoltam, colorpicker mintájára lesz majd filepicker.

Ez nekem nagy vesszőparipám, hogy jelenleg csak a Gtk és Qt filepicker az, ami általánosan támogatott a legtöbb szoftverben

LOL, a Gtk a legnagyobb fostalicska programozástechnikailag, amit valaha láttam. Konkrétan tudom, nézd csak meg, mi mindent kell gányolni, hogy egy program meghívja a fájlpickerét: https://gitlab.com/bztsrc/openmodal/-/blob/main/openmodal.h#L223 (Igen, fork()-ra és mmap()-re meg a direkt pollozásra valóban szükség van...)

A Qt filepicker-je még szarabb a Gtk-sénál is. Ami engem zavar, hogy miért drótozzák fixen ezekre. A filepicker olyan egyszerű, hogy lényegében csak néhány /elérési/út/fájl szrtinget ad át a hívó programnak, hagyhatnák, hogy a user azt drótozzon be magának, amit akar, saját kedvenc fájlkezelőjét vagy saját scriptjét. Ehelyett mindenkire rányomják ezeket a Qt-s, Gtk-s filepicker-megoldásokat, meg az portálos nyomorékságokat.

The world runs on Excel spreadsheets. (Dylan Beattie)

Tetszik a retróssága, csak hajrá. Írom ezt annak ellenére, hogy szerintem az én telemetriás projektemmel jobban jártál volna, könnyebb lett volna. Plusz én a GUI-tól elfordulok, CLI/TUI irányba tartok inkább, de hát mindenkinek más a fontos, más a workflow-ja.

A Nuklear-t konkrétan nem ismerem, de a 18k SLoC az nem valami sok, főleg nem egy komplett GUI toolkitnél. Ma már a legtöbb mainstream cucc millió kódsoros, ahhoz képest eltörpül. Csak az xterm, ami még nem is egy bonyolult program, 57k SLoC. Igaz ennek nagy része legacy ballaszt, meg sixel-kiegészítés, de akkor is mutatja az arányokat.

The world runs on Excel spreadsheets. (Dylan Beattie)

Tetszik a retróssága

Mire gondolsz? Teljesen személyre szabható, a színtéma, a betűtípusok is és ráadásul még bőrözhető is. https://bztsrc.gitlab.io/smgui#look_and_feel

de a 18k SLoC az nem valami sok, főleg nem egy komplett GUI toolkitnél

De, számomra sok. Ugyanazt a komplett GUI funkcionalitást megoldottam 2.5 SLoC-ból. Sőt, valójában még többet is, mert az enyém még HTML flow-t is tud, amit a Nuklear nem.

Raktam fel egy olyan screenshotot, ahol a keretek színét átállítottam ugyanarra, mint a háttér meg a gomb színe és FreeSerif fontot használ. Ettől most flat designú és hűde fasza menő trendi lett :-D
(A margó és az eltartás is állítható, ha valaki böszme nagyra és felületpazarlóra akarná esetleg állítani a gombokat...)

Az jutott eszembe, hogy attól lehet még retró érzésed, hogy ugyanazt a vga fontot használja alapból, mint a dosbox, ami eléggé retrós. Azért esett erre a választás, mert ha nem adsz meg semmilyen fontot, akkor alapból beágyazza az ASCII karakterek glifjeit, és ehhez mindenképp olyan fontra volt szükségem, ami kompatíbilis az MIT licensszel (na és persze ami kicsi, ez PSF2 formátumban lefordítva 2080 bájt csak).

Értem. Vannak azért hiányosságok benne, pl. nincs benne az a feature, ahol külső szerverről behúzott reklámokat és popupokat injektálsz random ablakokba, így a nagy cégeket nem fogja érdekelni. Keylogger sincs beépítve, az is hiányosság. AI-t nem integráltad bele, meg nem menő nyelven van írva. Az ilyet Rust-ban kell írni, vagyis csak azt konténerben futó a webasm/JS engine-t, ami JS-ként futtatja azt a Java VM-et, amiben a Javában megírt kódot futtatod, persze ezt is konténerizálva muszáj csinálni, meg agilisen kódolni, ha az AI-val generálod a kódot, az még jobb. Kötelező a babzsák is alád, fejlesztés közben, meg egy microsoft.com-os vagy Red Hat-es mailcím, mert anélkül a fejlesztő nem fejlesztő. Anélkül még bélgázt is tilos fejleszteni, nem hogy GUI toolkitet.

Ettől csak akkor tekintünk el, ha szénné matricázott M1-M3-as Macbook-on, MacOS alatt fejlesztetted, de végig a Startbucksban, zsáksapkában, meg kötött garbóban, bölcsésztarisznyával a válladon, de élő Twitch-streamben, ahol kamera is vette, ahogy a gépet püfölöd 8 órán át és a képernyőd is végig meg van osztva, illetve követelmény, hogy a Macbookot végig nem teheted töltőre, mert érzékelnie kell mindenkinek, hogy neked Mac-ed, van, hosszú akkuidővel, meg hogy nonkonform értelmiségi hipszter vagy, fontosch fejlesztő, digitális nomád. Viszont ekkor is csak Rust-ban vagy Haskellben engedélyezett a fejlesztés, és AI-t integrálni kell mindenbe.

The world runs on Excel spreadsheets. (Dylan Beattie)

MegaLike!

„Az összeomlás elkerülhetetlen, a katasztrófa valószínű, a kihalás lehetséges.” (Jem Bendell)

Nekem a C nagyon régen volt, akkor is csak egyetemi szinten, de még így is klassznak tűnik, gratulálok. :-)

Ha nem titok, milyen szoftvereket írsz, amikhez felhasználod?

Nekem a C nagyon régen volt, akkor is csak egyetemi szinten, de még így is klassznak tűnik, gratulálok. :-)

Kösz! Dobj egy csillagot a repóra, ha tetszik!

Ha nem titok, milyen szoftvereket írsz, amikhez felhasználod?

Hát, igazából több is van. Mármint készen vannak már, csak egyébként is újra akarom írni őket ilyen-olyan okokból.

- Az egyik a Scalable Screen Font Editor, amit elég nehézkes továbbfejleszteni, mert az UI egy korai kezdetleges változatára épül és jelen formájában nem lehet emscripten-el weboldalra lefordítani, amit pedig nagyon szeretnék.

- A másik az meg egy játékmotor (görgesd le), illetve a hozzá tartozó szerkesztő. Ez már megy emscripten-el, de a játékmotor felülete jelenleg nem eléggé rugalmas (a mostani projektbe emiatt került be a skinezhetőség, OSK illetve a gamepad támogatás); a szerkesztőnek meg az a baja, hogy remekül működik, csak épp iszonyat nehézkes használni, mert nem sikerült intuitívra a felülete. Ezeket meg emiatt akarom újraírni.

- A harmadik meg a Grand Unified Device Tree, egy multiplatform hardverleíró formátum, aminek van egy ablakos szerkesztője, de ez jelenleg GTK-s. Emiatt nem portolható, jó lenne ezt is lecserélni egy egyszerű, multiplatform UI-ra, valamint ezt is szeretném, hogy tudjon fordulni emscripten-el, weboldalba ágyazva (GTK-val erre esély sincs).

És ha már három projektemben is igény van rá, akkor jobbnak láttam csinálni egy külön repót és lib-et az UI-nak, amit aztán mindben felhasználhatok majd. És talán másoknak is hasznára válik :-)

Na, egy kis frissítés.

- szerkesztett szövegre kattintva odamozgatja a kurzort (proporcionális fontokkal és multibyte karakterekkel ez nem is volt annyira triviális, mint gondolnánk)
- új mező: UI_BTNTGL, ez pont ugyanolyan kapcsoló, mint az UI_TOGGLE, csak úgy néz ki, mint az UI_BUTTON
- új mező: UI_PATH, ez a fájlválasztó WIN32 és POSIX API-ra is megírva, UNICODE és UTF-8 támogatással, gyorskereséssel, kiterjesztésszűréssel stb.
- új mezö: UI_FILE, ez a színválasztó mintájára egy szöveges beviteli mező, ami azonban felhoz egy UI_PATH-ot is, és abban kattintgatva szerkesztődik a tartalma, pont, mint ahogy a színválasztónál is
- pár apró hibajavítás, főként egy pixel ide, ide pixel oda jellegűek
- frissített dokumentáció

A fájlválasztónál Linux alatt a gyökér a [/] gomb, míg Windows alatt két gyökér gomb van, pl. [C:] [\]. Utóbbi úgy működik, ahogy a Linuxos [/] gomb, azaz a főkönyvtárba dob, míg az első gomb egy meghajtólistát hoz be. Sajnos nem jutott eszembe, milyen ikonú lehetne egy partíció, szóval ezekhez is csak könyvtárikon van jelenleg. Ha valakinek van ötlete, szeretettel hallgatom! (Az nem fér bele, hogy meghajtótípusfüggő ikon legyen, pl. pendrive, winyó, CD stb., egy egységes ikon kell.)

Hajrá! Néhányszor elgondolkodtam, hogyan lehetne az FTXUI C++ TUI library mintájára valami ehhez hasonló suckless C libet csinálni (ncurses meg notcurses és más amit még találtam nevetségesek). Pythonos Textual sajnos elég nagy bloat és sajnos sok widget nincs.

Csináltam már olyant is, bár az inkább dialog / zenity / stb. vonalon mozgott, nem független UI libként szolgált. Nem használtam ncurses-t hozzá, csak simán printf, és az escape szekvenciákat limitáltam a VT100 szabványra (de runtime állítható VT52-re is). Amit nem sikerült megoldani így, az az ablak méretének lekérése (elvileg van rá szekvencia, de kevés terminál emulátor tudja), így az Linux ioctl lett. Minden más hordozható benne.

Minden egyszerű függvényekbe lett burkolva, pl drawchklist() - kirajzol egy checkboxlistát, ctrlchklist() - a kontrollere, stb. Így néz ki: https://gitlab.com/bztsrc/osz/-/raw/master/docs/oszcfg1.png https://gitlab.com/bztsrc/osz/-/raw/master/docs/oszcfg2.png

szuper! viszont kicsit koszkodnek is :)

- langauge -> language  (screenshotokon el van irva)

- "state mode" ez mi lenne? sose hallottam/lattam ilyen kifejezest, gugli is csak irrelevans dolgokat hoz ra. biztos igy hivjak?

- tenyleg nagyon retro a kinezete, a screenshtotok az amiga os-re vagy a 90-es evek dos-os progijaira emlekeztet :)

- langauge -> language (screenshotokon el van irva)

Ehhh, valóban elírtam a widgets demóban https://gitlab.com/bztsrc/smgui/-/blob/main/examples/widgets.c#L50 nem tűnt fel. A screenshotok arról készültek. Köszönöm, hogy szóltál!

- "state mode" ez mi lenne?

Mindjárt a README elején el van magyarázva, illetve a magyar nyelvű doksi nyitóoldalán is: A státusz-vezérelt UI alapelve az, hogy már úgyis megvannak a változóid, szóval elég csak hivatkozni azokra egy űrlapból, nem kell sem visszahívás sem azonnali kódlekezlés, csupán csak azon már meglévő változók értékei vezérlik a GUI megjelenítését.

- tenyleg nagyon retro a kinezete, a screenshtotok az amiga os-re vagy a 90-es evek dos-os progijaira emlekeztet :)

Ezen a képen is? Mondom én, a betűtípus lesz a ludas, dosbox-ból való. Bármikor lecserélhető másra, és a nyomógombok keretei is kikapcsolhatók.

Hát, FreeSerif szabad licenszű. MS fontot direkt nem akartam használni.

akkor az inkabb state-driven lesz angolul, nem? olyat mar lattam legalabb :)

Nem, mert a "state-driven" egy már létező kifejezés, ami tök mást jelent. (Egyébként szó szerinti fordításban az lenne, de az nem fejezné ki, hogy kéirányú dologról van szó, azaz a változó határozza meg a GUI státuszt valóban, de itt fordítva is megy a dolog, a GUI visszahathat a változóra.)

aha, csak ezen inkabb WinCE mint DOS ;)

Rakhatsz rá WinXP, Vista meg akár Win11 skin-t is, ha akarsz (aztán majd ne lepődj meg, ha dörömbölnek az MS jogászai az ajtódon ;-)). A lényeg, hogy szabadon konfigurálható, amit csak akarsz.

Lájkolom. Engem is érdekel a kifejtése annak, hogy mi a "state mode" meg az "immediate mode" között a különbség?

A multithreading hogy működik? Az összes általam ismert UI toolkit egyszálú, és mindent ami nem azonnali reakció, azt háttérszálra kell tenni. (js esetén ráadásul már a nyelv szintjén is így van ugye...) Ezt értem, és ezzel a logikával csináltam az összes UI-t eddig. Mire és hogyan kell a multithreadinget használni?

Engem is érdekel a kifejtése annak, hogy mi a "state mode" meg az "immediate mode" között a különbség?

Immediate mode esetén ezt csinálod (a példa a Nuklear mintakódja):

enum {EASY, HARD};
static int op = EASY;

nk_layout_row_dynamic(&ctx, 30, 2);
if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD;

azaz csinálsz egy változót, majd függvényhívással megjeleníted és "if" ágban lekezeled a kattintás eseményt, és beállítod a változót.

Ezzel szemben state-mode esetén csinálsz egy layout-ot, ami hivatkozik a már meglévő változódra:

{ .ptr = &op, .value = EASY, .type = UI_RADIO, .label = EASY_TITLE },
{ .ptr = &op, .value = HARD, .type = UI_RADIO, .label = HARD_TITLE },

És kész is, mész a dolgodra, nincs más teendő, nem kell semmiféle eseménylekezelőt írnod, a GUI a változó értéke alapján magától generálódik, és a GUI eseménykezelője magától állítja a változó értékét, neked semmi dolgod.

A multithreading hogy működik?

Párhuzamos szálakat indítasz.

Az összes általam ismert UI toolkit egyszálú

És jó szar is mind. Itt semmi akadálya, hogy az egyik szálon futó GUI által beállított változó értékét egy másik szálon kérd le, vagy hogy az egyik szálon beállított érték alapján a másik szálon futó GUI megfelelően jelenítse meg a check box-ot vagy akármit.

Mire és hogyan kell a multithreadinget használni?

Bármilyen művelet esetén. Tipikus fostalicska Windows példa erre, hogy amikor fájlt próbálsz másolni, és elkezded mozgatni az ablakot, akkor leáll és szünetel másolás, míg abba nem hagyod az ablak csesztetést.

Jobb helyeken az egyik szálon fut a GUI és megjeleníti a progress bar-t, míg egy másik szálon meg történik az érdemi munkavégzés. Ha mozgatod az ablakot, akkor nálam attól még nem áll le a munkavégzés.

Az a baj a többszálúsággal, hogy lehetnek nem kiszámítható sarokesetek, versenyhelyzetek. Ezek miatt nagyon észnél kell lenni. Például ha felveszel dinamikusan elemeket egy listába (választó lista elemei), akkor azt az adatszerkezetet szinkronizálnod kell, azaz többszálúság-állóvá kell tenned. Ez nem mindig triviális. Ha csak egyetlen egy szinkronizálási hiba bennemarad, akkor az lehet egy akna, ami mondjuk 1000 használatból egyszer felrobban.

Én jelenleg úgy vagyok vele, hogy többszálúságot csak akkor használok, ha nagyon muszáj, és akkor is nagyon megfontoltan. Egy GUI esetén semmi nem indokolja a többszálúság szükségességét. Feltételezve, hogy van egy aszinkron API-nk mint Javascriptben. Azt is érdemes tudni, hogy a szálak közötti üzengetés rendkívül költséges, mérted is, hogy nem jár hatékonyságvesztéssel, vagy csak úgy mondod?

Alapból egyszálú a modell, vagy eleve az a modell, hogy vagy egy UI szál, és a program többi része külön szálon fut?

A sucklessel az a bajom, hogy nem feltétlen sikerül betartania az ígéretét: SXMO-t próbáltam PinePhone-on használni, és hát annyira nagy szopás volt, mint semmi más, pedig azzal reklámozzák, hogy suckless. Az alap koncepció jó is lenne, ha működne úgy, ahogy ígéri. Csak sajnos nem működik, tök lassú, és minden bizonnyal versenyhelyzet szituációkkal van tele, mert random elhasal benne minden. Nem azt mondom, hogy a te UI-os is rossz, hanem hogy a suckless elnevezés máris le lett járatva.

Az a baj a többszálúsággal, hogy lehetnek nem kiszámítható sarokesetek, versenyhelyzetek.

Ez általánosan igaz bármilyen többszálúságra, semmi köze az SMGUI-hoz. Ha több szálon akarod matatni a layout-ját, az a Te dolgod, Neked kell a szemaforokra odafigyelni. Maga az SMGUI sohasem ad hozzá vagy vesz el ebből a listából. Sőt, akárhány ilyen listád lehet, és váltogathatod is őket (egyik tab, másik tab stb.)

Egy GUI esetén semmi nem indokolja a többszálúság szükségességét.

Dehogynem. Lenyomja a gombot a felhasználó, és amíg végrehajtod, amit ilyenkor végre kell hajtani, addig nem válhat müködésképtelenné a felület. Immediate-mode esetén erre esélyed sincs, amíg a végrehajtás tart, addig szükségszerűen lefagy a felület. Callback-nél nem, de azt meg szopás használni, külön függvény kell minden gomblenyomáshoz meg check box kattintáshoz stb.

Feltételezve, hogy van egy aszinkron API-nk mint Javascriptben.

Már tisztáztuk, hogy minden aszinkron API - a Javascript motorok pedig különösképpen -, erdendően többszálúak. (Akkor is, ha a többszálúság csak a motorháztető alatt található és nincs direktben kivezetve a JavaScript API-jára, még akkor is. De egyébként pont a JavaScript async API-járól ORDÍT, hogy többszálú, mit gondolsz, a Promise miért closure és nem kontrollstruktúra?)

Alapból egyszálú a modell, vagy eleve az a modell, hogy vagy egy UI szál, és a program többi része külön szálon fut?

A modell az, hogy teljesen tök mindegy, hogy a program többi része egyszálú vagy többszálú-e. (Nincs globális állapot, csak kontext, és az egyetlen függvény, ami különböző szálakról is hívható, egy atomi művelettel állít egy bitet egy volatile változón és ennyi.)

Amit a sucklessről írsz, annak se füle, se farka. Kb. mintha azt mondanád, hülyeség az egész foci VB, mert az egyik csapat tök béna. Na kb. ennyi értelme van annak, amit itt írtál.

Lenyomja a gombot a felhasználó, és amíg végrehajtod, amit ilyenkor végre kell hajtani, addig nem válhat müködésképtelenné a felület.

vs a stackoverflow kérdésben, amivel lent vitatkozol:

For example, Java Swing and Android UI both use a single threaded model where a single UI thread is responsible for updating all the UI. What made the framework designers chose one thread model over the other?

Biztos, hogy ugyanazt értitek többszálú UI alatt? Szerintem az nem a te találmányod, hogy amikor lenyomok egy gombot, akkor a bármi-ami-lassú-művelet nem a UI threaden fut le, és blokkolja azt. Sőt, a hivatkozott példákban még egy háttérben futó szál is képes a UI-ra így-úgy juttatni változtatást.

Persze, hogy nem az én találmányom. Én csak igyekeztem minnél hatékonyabban és minnél kevesebb kóddal megvalósítani a már meglévő best practice-t.

De mégegyszer, az UI-nak édesmindegy, hogy egyszálú vagy többszálú-e a programod. Ahol kellett, ott odafigyeltem, hogy ne legyen baj akkor se, ha több szál hívja, de ha akarod, akkor egyetlen szálból kezelheted az egész UI-t (lásd multiwin.c példaprogram). Ha akarod, akkor külön szálon kezelheted az egyes ablakokat. Ha akarod, akkor ugyanarra az ablakra rakhatsz ki mezőket különböző szálak által kezelt változókból. Tökmindegy, az UI-nak nem számít, úgy lett megtervezve (nincs globális státusz, csak kontextusból dolgozik, nincsenek külön függvényhívások, amik összeakadhatnának, stb. stb. stb.).

Az összes általam ismert UI toolkit egyszálú

És jó szar is mind. Itt semmi akadálya, hogy az egyik szálon futó GUI által beállított változó értékét egy másik szálon kérd le, vagy hogy az egyik szálon beállított érték alapján a másik szálon futó GUI megfelelően jelenítse meg a check box-ot vagy akármit.

Ezen a gondolatmeneten mások már 30 éve átestek, érdemes elolvasni az alábbiakat. Lehet, hogy van benne valami, vagy persze az is lehet, hogy te vagy okosabb mindenki másnál :)

https://stackoverflow.com/questions/5544447/why-are-most-ui-frameworks-…

https://web.archive.org/web/20120122082554/http://weblogs.java.net/blog…

 

Tipikus fostalicska Windows példa erre, hogy amikor fájlt próbálsz másolni, és elkezded mozgatni az ablakot, akkor leáll és szünetel másolás, míg abba nem hagyod az ablak csesztetést.

Legalább a Windows 8 óta, tehát bőven több mint 10 éve a beépített másolásnak elég jó aszinkron GUI-ja van, ami nem szenved ettől a problémától. De amúgy való igaz, pont az ilyesmi részek azok, amik ha nem jól vannak csinálva, okozhatnak felesleges és érthetetlen lassulást meg befagyást.

Ezen a gondolatmeneten mások már 30 éve átestek, érdemes elolvasni az alábbiakat.

Minek? Amin ezek agyalnak, azt én konkrétan megvalósítottam.

elég jó aszinkron GUI-ja van, ami nem szenved ettől a problémától

azaz magyarul többszálú. Egyébként az SMGUI jobb ennél, mert nem követeli meg a többszálúságot, mint az általad emlegett Win API, sőt, egyáltalán nincs suüksége agyonbonyolított aszinkron API-ra se.

Szabadon dönthetsz arról, hogy akarsz-e többszálat implementálni vagy sem. Ott használod a változód, ahol akarod és kész. Erre mondják, Keep It Simple Stupid.

Láthatóan nem vetted a fáradságot, hogy elolvasd, amit linkeltem. Vagy nem értetted meg.

azaz magyarul többszálú.

Súlyos tévedés, hogy az aszinkron azt jelenti, hogy többszálú, pl. hogy több szálról kezelnéd a GUI-t. Arról szól, hogy a helyes esetben háttérben végzendő dolgok, tipikusan I/O nem szinkron módon vannak meghívva a GUI-ról. Javaslom nézz utána a fogalmaknak, mielőtt összevissza beszélsz.

az általad emlegett Win API

Nem mondtam semmit a Win API-ról. Egy példát hoztam arra, hogy a Windows-ban hogyan néz ki manapság egy helyesen implementált GUI elem, szemben mondjuk a 25 évvel ezelőtti implementációjával.

Láthatóan nem vetted a fáradságot, hogy elolvasd, amit linkeltem. Vagy nem értetted meg.

Láthatóan nem értetted meg, hogy miután letettem az asztalra egy működőképes multithread-es megoldást, nem is érdekel.
Szakmai karrierem 99%-ban balfaszokat hallgattam, akik azt próbálták megmagyarázni, miért nem lehetséges megoldani azt, amit épp megoldottam.

Súlyos tévedés, hogy az aszinkron azt jelenti, hogy többszálú

Súlyos tévedés, hogy az asszinkronnak lenne bármiféle értelme többszálúság nélkül. (Lett légyen az multithread, multiprocess, lightweight process, akármi.)

hogyan néz ki manapság egy helyesen implementált GUI elem

Súlyos tévedés! Egyáltalán nem is létezik olyan, hogy "helyesen implementált". Sokféle megoldás létezik, mindnek van előnye és hátránya is. Én úgy döntöttem, a K.I.S.S. alapján implementálom az enyémet, ami sem nem callback-driven, sem nem immediate-mode lesz, mert nekem így tetszik, ezt a legkevesebb szopás illeszteni.

Ha neked más igényed van, mint nekem, akkor használj másik libet és kész. Ott a GTK, az sem immediate-módú, cserébe van legalább 1 gigányi függősége. Vagy a QT, ami szintén nem immmediate-mode, cserébe véget nem érő szopás C-ből használni (name mangle és egyebek).

működőképes multithread-es megoldást

Azért nekem csak gyanús lenne, ha a szakma 99%-a hosszú évtizedetek óta kerülgeti a problémát, akkor hogyhogy sikerült pont neked pont most megoldani. És ráadásul akkora arccal kinyilatkoztatni, hogy az ajtón sem fér be.

Súlyos tévedés, hogy az asszinkronnak lenne bármiféle értelme többszálúság nélkül.

Csak egy egyszerű példát mondok: JavaScript. Teljesen egyszálú, mégis minden I/O művelet aszinkron benne.

De tudod mit, igazából tényleg a B változat igaz: mindenkinél okosabb vagy. Ami különösen figyelemreméltó teljesítmény úgy, hogy a téma alapfogalmaival sem vagy tisztában.

Azért nekem csak gyanús lenne, ha a szakma 99%-a hosszú évtizedetek óta kerülgeti a problémát

Azért nekem gyanús, hogy semmi tapasztalatod sincs, úgy állítod ezt.

Csak egy egyszerű példát mondok: JavaScript. Teljesen egyszálú

ROTFL, ezen megfeküdtem a röhögéstől. Láttál Te már JS motort közelről?
Na, jót röhögtem rajtad troll, most már megyek, mert fontos dolgaim is vannak ;-) (Meg elfogyott a popcorn)

Esetleg valami érv, vagy ellenpélda?

A JavaScript motor implementációjának nincs köze ahhoz, hogy a JavaScript programozási modellje egyszálú, aszinkron IO. És hogy mondjuk a JavaScript GC adott esetben több szálon van implementálva, vagy mondjuk a JIT-hez használ háttérszálat a JavaScript motor, az sem befolyásolja, hogy az IO műveletekhez nem kell több szál, még a JavaScript engine szintjén, belül sem.

Nem érted, hogy az aszinkron nem azt jelenti, hogy egy másik szálon elindítom a műveletet, és az a másik szál blokkolva (szinkron módon) várakozik az IO befejezésére, aztán majd ha végzett, akkor valahogy koordinálok a szálok között, multithreading koordinációs eszközökkel. Aszinkron IO-nál nincs másik szál. De próbáld ki nyugodtan egy elterjedt JavaScript engine-ben, hogy indítasz 10 network hívást egyszerre, és megnézed debuggerrel az OS thread-eket. Akkor nem az lesz, hogy lesz egy GUI szálad, meg lesz 10 másik szálad, amik a call stack tetején blokkolva várakoznak arra, hogy befejeződjön az IO.

"figyelemreméltó teljesítmény úgy, hogy a téma alapfogalmaival sem vagy tisztában."

Aszinkron IO-nál nincs másik szál. De próbáld ki nyugodtan egy elterjedt JavaScript engine-ben, hogy indítasz 10 network hívást egyszerre

Nincs több szál, de azért párhuzamosan futtatsz 10 dolgot egyszerre... Ugye azért itt most te is kapisgálod már, mekkora faszságokat irogatsz?

Nincs több szál, de azért párhuzamosan futtatsz 10 dolgot egyszerre... Ugye azért itt most te is kapisgálod már, mekkora faszságokat irogatsz?

Eddig is szép sebességgel haladtál, de most csattantál csak igazán tátott szájjal abba a bizonyos erdőbe.

Képzeld el, hogy pont így van. Egyszerre fut 10 network kérés, és nincs 10 szál hozzá. Megértem, hogy hihetetlen számodra, mert fogalmad sincs erről az egész koncepcióról, az egész párbeszédből lejött már az elején, hogy nem érted az aszinkron IO jelentését.

De tudod mit, ne higgy nekem, hanem higgy a saját szemednek. Próbáld ki, amit előbb írtam. Egy egyszerű nodejs program, ami megnyit egyszerre sok hálózati kapcsolatot. És nem fog sok szálat használni.

Egyszerre fut 10 network kérés, és nincs 10 szál hozzá.

Meséld már el kérlek, ugyan mégis hogy csinál 10 network kérést párhuzamosan a JS motor, ha csak egyetlen szállal rendelkezik össz-vissz?
Kíváncsian hallgatlak! (Popcorn bekészít)

fogalmad sincs erről az egész koncepcióról

ROTFL

Úgy, hogy mondjuk egy ciklussal meghívod 10-szer new net.Socket().connect(...) metódust? Képzeld, ilyenkor az egyetlen szál elindít több hálózati kapcsolatot, de nem várja meg a következő indításával, hogy az előző sikeresen vagy sikertelenül befejeződjön. És nem lesz 10 háttérszál sehol, OS szinten sem, ami arra vár, hogy a connect rendszerhívás befejeződjön. Pedig 10 folyamatban lévő connect-ed van. Tehát ismét, van egy szálad, és sok folyamatban lévő hálózati kapcsolatod. Nahát, hiszen pont ez az aszinkron IO. És ha valamelyik tovább jut, mondjuk sikeresen csatlakozik, vagy valami hiba van, akkor az az egyetlen szál kezeli majd ezt az eseményt.

Úgy, hogy mondjuk egy ciklussal meghívod 10-szer new net.Socket().connect(...) metódust?

Ezen besírtam a röhögéstől!!!! A kérdés konkrétan az volt, a JS motor hogy oldja meg a háttérben több szál nélkül ezt, nem az, hogy a vérpistikék mit kopipasztáznak össze-vissza hozzá JS oldalon :-D :-D :-D

ilyenkor az egyetlen szál elindít több hálózati kapcsolatot, de nem várja meg a következő indításával, hogy az előző sikeresen vagy sikertelenül befejeződjön.

MESTER, TANÍTS!

És nem lesz 10 háttérszál sehol, OS szinten sem, ami arra vár, hogy a connect rendszerhívás befejeződjön.

Anyám... Na idefigyelgy, ha EGY szálad lenne, akkor nem lenne párhuzamos futás, és akkor kéne megvárnia a 10 kapcsolatnak, hogy az egyik végezzen, mire a következő indulhatna.
Többszálú JS motor esetén lehetséges csak, hogy nincs várakozás, és egy másik szálon új kapcsolat indul mielőtt még az előző végezne, mert független szálakon futnak... Teccik érteni?

Az egyetlen lehetséges megoldás az egy szálra egyébként a multiplexelés lenne a select() rendszerhívás használatával, de úgyse hiszem el, hogy bármi fingod lenne erről (még csak véletlenül sem ezt mondtad), de még ha ezt a helyes választ mondtad volna is, akkor is kizárt, hogy bármelyik JS motor ilyen elavult és legkevésbé sem hatékony megoldást használna az async IO implementálására.

Tessék, nehogy megszólj, hogy én is csak pofázok, itt a bizonyíték a SpiderMonkey forrásából:
https://searchfox.org/mozilla-central/source/dom/media/webrtc/transport…

void WebrtcTCPSocketWrapper::AsyncOpen(
    const nsCString& aHost, const int& aPort, const nsCString& aLocalAddress,
    const int& aLocalPort, bool aUseTls,
    const shared_ptr& aConfig) {
  if (!NS_IsMainThread()) {
    MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch(
        NewRunnableMethod>(
            "WebrtcTCPSocketWrapper::AsyncOpen", this,
            &WebrtcTCPSocketWrapper::AsyncOpen, aHost, aPort, aLocalAddress,
            aLocalPort, aUseTls, aConfig)));
    return;
  }

Hmmm, a "mMainThread->Dispatch" vajon mi...? Hogy is mondtad, "És nem lesz 10 háttérszál sehol, OS szinten sem", még hogy nem, mi? LOL

De legyen, nézzünk másikat is, szerinted a V8 motor ezen forrásfájla mit is implementál?
https://github.com/v8/v8/blob/main/src/libplatform/worker-thread.cc

WorkerThread::WorkerThread(TaskQueue* queue)
    : Thread(Options("V8 WorkerThread")), queue_(queue) {
  CHECK(Start());
}

Vagy épp ez (a kód nehezebben olvasható, de a komment rohadtul egyértelmű):
https://github.com/v8/v8/blob/main/src/objects/js-atomics-synchronizati…

void JSAtomicsMutex::HandleAsyncNotify(LockAsyncWaiterQueueNode* waiter) {
  Isolate* requester = waiter->requester_;
  HandleScope scope(requester);

  if (V8_UNLIKELY(waiter->native_context_.IsEmpty())) {
    // The native context was destroyed, so the promise was already removed. But
    // it is possible that other threads are holding references to the
    // synchronization primitive. Try to notify the next waiter.
    if (!waiter->synchronization_primitive_.IsEmpty()) {
      DirectHandle js_mutex =
          waiter->GetSynchronizationPrimitive();

De persze ez sem többszálú JS motor, mi? LOL

Olyan vagy az aszinkron IO kapcsán, mint az egyszerű bácsi, aki csak áll az állatkertben, és ismételgeti a zsiráfra, hogy ilyen állat márpedig nincs. Pedig hidd el, hogy nincs annyi szál, ahány IO-d van folyamatban.

Bár van némi fejlődési potenciál benned, mert elindultál a helyes irányba, a select megtalálása 1. lépésnek jó volt. Mondjuk a párhuzamos IO kezelésére a párhuzamos szálak használata a 0. lépés hatékonysági sorrendben, hiszen annyi szálat kéne fenntartanod, ahány párhuzamos IO műveleted van, és mindegyik csak aludna valójában, mert IO-ra várva blokkol. Nem is szokták csinálni.

A select mondjuk 1. lépés, ahogy írod rég elavult. Nyugodtan keress rá, hogy vannak modernebb, általában OS függő alternatívái. (Azt nem is minősítem, hogy azt állítod, hogy én ezt nem is ismerhetem. Ezt hogy következtetted ki a hozzászólásaimból? Nincs hely és idő teljes ismeretterjesztő leckéket adnom neked, és _mindent_ leírnom, amiről van ismeretem.) És tipikusan egy modern JavaScript motor ezen modern alternatívák közül fog valamit használni.

A kódrészletekhez: a Dispatch nem azt jelenti, hogy új szálat indítunk. Azt jelenti, hogy meglévő szálon futtatunk valamit.

De a V8-os példád, hogy létezik a worker thread fogalma sem erősíti vagy cáfolja a több szál és több IO kérdését. Mint írtam korábban is már, igen, a JavaScript engine-ek használnak több szálat, a megfelelő helyen a megfelelő célra. De nem az aszinkron IO-ra.

Továbbra is azt javaslom, amit korábban, és ami végleg eldönti a kérdést a gyakorlatban is: a sok ROTFL és LOL közepette kérlek próbáld ki egy egyszerű nodejs programban, hogy indítasz 10 hálózati kérést, amik egyszerre vannak függőben, és nézd meg debuggerrel, hogy lesz-e 10 új OS szálad, amíg futnak azok a hálózati kérések. (Hint: én megtettem)

Kérlek akkor válaszolj erre, ha ez a próbád lefutott, és írd meg az eredményt.

Nincs hely és idő teljes ismeretterjesztő leckéket adnom neked,

MUHAHAHAHAHAHA! Mintha egyáltalán képes lennél erre! :-D Barátocskám, Te sosem leszel olyan szinten.

De nem az aszinkron IO-ra.

LOL. Konkrétan bemásoltam, hogy a "HandleAsyncNotify" szinkronizációs primitíveket használ. Nyilván azért van erre szüksége, mert egyetlen szálon fut az async IO implementációja. (Szarkazmus, má' megin')

Azért azon megfeküdtem a röhögéstől, hogy egy olyasvalaki, aki még azt a kódot sem képes értelmezni, amit az orra elé tolnak, na, egy ilyen azt képzeli magáról, hogy oktathat engem programozásból :-D
Ez az évszázad vicce volt, de most komolyan! :-D :-D :-D

Elmondanád mégegyszer, milyen projekteket tettél le eddig az asztalra, hogy ilyen nagy az arcod?

Loop: Kérlek akkor válaszolj erre, ha ez a próbád lefutott, és írd meg az eredményt.

Miért kéne amúgy bármit állítanom arról, hogy eddig mit tettem le az asztalra? Attól erősebb lesz az érvem a jelen topikban? (Nem). Kérlek ne a személyemmel vagy egyéb eddigi tevékenységeimmel vitatkozz, hanem a tényszerű állításaimmal.

Én amúgy elhiszem, hogy sokat programoztál, és elismerem, hogy sok hasznos dolgot csináltál. Azt meg főleg elhiszem, hogy ehhez elképesztő nagy arcod is van. De most ezek senkit nem érdekelnek.

Miért kéne amúgy bármit állítanom arról, hogy eddig mit tettem le az asztalra?

Talán hogy ne tűnj komplett nagypofájú idiótának, esetleg? Szóval? Mit tettél le eddig az asztalra, ami igazolná is az állítólagos szakmai tudásod?

Még ezek után a röhejes kaffogásaid után is megkapod a lehetőséget, hogy bizonyíts, miért nem élsz vele?

elképesztő nagy arcod is van

Azt hiszed, nekem van nagy arcom? Mondd csak, néztél Te már tükörbe?

mit befolyásolna bármiféle szakmai referencia?

Mondjuk hogy nem néznének totál hülyének, aki a nem is létező tekintélyére próbál csak hivatkozni, miközben semmit sem tud felmutatni?

Magyarán hülyét csináltál magadból, de az a része végtelenül szomorú, hogy ezt még külön el is kell magyarázni neked...

Loop: Kérlek akkor válaszolj erre, ha ez a próbád lefutott, és írd meg az eredményt.

Hol hivatkoztam a tekintélyemre? Nézz tükörbe, ezt pont te csinálod megállás nélkül, te hivatkozol folyton arra, hogy mekkora ász vagy, és milyen sokat programoztál már, és hozzád képest senkik vagyunk. Én sosem hittem a tekintélyelvűségben. Szakmai állításokat tettem a témában. Próbálj azokra az állításokra reagálni.

Egyébként miért félsz annyira megcsinálni az említett próbát?

Zsenge ifjúkoromban én is csináltam egy multithread UI keretrendszert, de később beláttam, hogy nem jó és inkább átalakítottam egyszálúra.

Hogyan akarod bizonyítani, hogy helyesen működik a programod? Az, hogy 50-szer jó volt nem jelenti azt, hogy 51-szer is jó lesz. Bizony kimerítően tesztelni kell, amit egyszemélyes projektekben lehetetlen csak a mennyiség miatt is. Ha többszálúság van, akkor a versenyhelyzetek kizárása teszteléssel nem is lehetséges, hanem "matematikai" bizonyítás kell rá. Megcsináltad ezt, azért mondod, hogy működőképes a megoldásod, vagy csak kincstári optimizmusod van?

Zsenge ifjúkoromban én is csináltam egy multithread UI keretrendszert, de később beláttam, hogy nem jó és inkább átalakítottam egyszálúra.

Már zsenge ifjúkorom óta úgy írom az UI-kat, hogy tökmindegy legyen nekik, egyszálú vagy többszálú alkalmazásban használják-e.

Hogyan akarod bizonyítani, hogy helyesen működik a programod?

Pontosan ugyanúgy, ahogy a Microsoft bizonyította a GDI-je esetén.

(Szarkazmus. Teljesen irreális és idiótaság, hogy olyant várnál el tőlem, amire még a kibebaszottsokpénzzel kitömött gigavállalat sem képes...)

Nem volt nehéz, ugyanis a GDI egy szálról használandó.

MUHAHAHAHA
1. Hol az a híres neves GDI helyességbizonyítás, amire vered a nyálad? Merthogy konkrétan tudom, nem is létezik!
2. De ha lenne, miért is lenne más egy vagy több szál esetén? Pont ugyanaz, elárulom (veled ellentétben Én már végeztem programhelyességbizonyítást, tudom, mi fán terem a fótizmus)
3. Ne hagyd, hogy megzavarjon az az aprócska tény, hogy például ebben a projektemben több szálról használom a GDI-t! Nyilván szopás, de nem lehetetlen.

Csak ismételni tudom magam: "Szakmai karrierem 99%-ban balfaszokat hallgattam, akik azt próbálták megmagyarázni, miért nem lehetséges megoldani azt, amit épp megoldottam."
Igen, a többszálas GDI is pont egy ilyen tipikus eset. Szerinted nem létezik, én meg megcsináltam. (A közben megszerezett tapasztalatokat pedig felhasználtam az SMGUI megalkotásánál.)

Ha a szövegértésed helyes lenne, akkor értenéd, hogy azt írtam, hogy azért volt egyszerű a GDI "többszálúság" "helyességbizonyítása", mert csak annyi a leírás, hogy használd egy szálról, és akkor jó lesz.

Megpróbálhatod több szálról is használni, de folyamatosan aknákat kell kerülgetned, pont ahogy te is írtad egyébként. Nem véletlenül vannak az ajánlások. És ha tényleg odafigyelnél, nem írtam, hogy tilos több szálról használni, vagy hogy nem is létezhet ilyen. Csak annyit írtam, hogyan célszerű használni.

Ha a szövegértésed helyes lenne, akkor értenéd, hogy azt írtam, hogy azért volt egyszerű a GDI "többszálúság" "helyességbizonyítása"

Ha a szövegértésed helyes lenne, akkor most prezentáltál volna egy linket erre az állítólagos "helyességbitonyításra", kaffogás helyett. Persze nem mintha azt vártam volna, hogy képes lennél rá, mert pontosan tudom, hogy nem is létezik.

Mondom én, magyar nyelvű szövegértés egyes, leülhetsz. Egy szálra mutass helyességbizonyítást! Arra sem tudsz, mert nem létezik!
Egyébként az is eleve hazugság, hogy a GDI egy szálról használandó, lásd MSDN, Win2000 óta minden NT kernel user32.dll-je támogatja a SendMessage, PostMessage, PostThreadMessage hívásokat.

Egy szálra mutass helyességbizonyítást

Miért kéred, hogy mutassak, ha az egész szál onnan indult, hogy a többszálúságra kell neked helyességbizonyítás? Az alábbiak nem az én szavaim:

én is csináltam egy multithread UI keretrendszert, de később beláttam, hogy nem jó

Hogyan akarod bizonyítani, hogy helyesen működik a programod?

Pontosan ugyanúgy, ahogy a Microsoft bizonyította a GDI-je esetén

Egyébként a PostMessage és társai nem arról szólnak, hogy több szálról kezeled a GDI dolgokat. Arra vannak szánva, hogy az egyetlen szálra, ami kezeli a GDI dolgokat, elhelyezel egy üzenetet, és amikor az az egyetlen szál odajut, hogy feldolgozza azt az üzenetet, akkor majd csinál a GDI objektumokkal valamit. Oh wait, de hiszen ez pont az, hogy a GDI objektumokat egyetlen szálról kezeled.

ha az egész szál onnan indult, hogy a többszálúságra kell neked helyességbizonyítás

Egész pontos legyek, onnan indult, hogy a helyességbizonyításra azt mondtad, "Nem volt nehéz, ugyanis a GDI egy szálról használandó" (be is linkeltem, nehogy eltévedj). Na akkor hol is van az a bizonyos bizonyítás? Eddig csak fostad a szót róla, de semmi kézzelfoghatót nem prezentáltál.

(Költői kérdés csak, tökéletesen tisztában van vele mindenki, hogy soha nem is létezett ilyen a bizonyítás, se többszálra, se egyszálra; és hogy a GDI nem is egy szálról használandó, mintkettő pusztán csak a beteg agyad szüleménye. Légy egész nyugodt, ezzel mindenki tisztában van itt a HUP-on :-D)

Egyébként a PostMessage és társai nem arról szólnak, hogy több szálról kezeled a GDI dolgokat.

Most aztán alaposan öntökönszúrtad magad :-D Ideidézem neked az MSDN-t (kiemelés tőlem): "PostMessageA function (winuser.h) - Places (posts) a message in the message queue associated with the thread that created the specified window". Semmi köze a többszálhoz, mi? LOL

Iszonyat szórakoztató, ahogy hülyét csinálsz magadból és még a topikom is főoldalon tartod közben >D

Nem volt nehéz, ugyanis a GDI egy szálról használandó

Lehet pontosabban kellett volna fogalmaznom, mint kb. egy jogász, és neked is akkor átjött volna, hogy ezt egy egyszerű és gyors válasznak szántam a GDI-t több szálról használóknak, hogy a GDI-t valójában egy szálról célszerű használni, és így helyes lesz. Nem akarom ezt többször megismételni.

És igen, captain obvious újra, egy szálról kezelve sincs matematikai helyességbizonyítása a GDI-nak, legalábbis én sem tudok róla. Legalább van valami amiben egyetértünk :)

Nem állítottam, hogy a PostMessage-nek nincs köze a több szálhoz. A Windows támogatja a szálak használatát, tehát nyilván lesznek benne olyan API hívások, amik szálkezeléssel kapcsolatosak. Itt függvénynevek és leírások random bemásolásánál több kell, hogy jól tudj érvelni. Érteni is kéne, hogy melyik mire való.

De mivel nem érted, ezért sajnos az állításom lényege nem ment át, így leírom újra: a PostMessage mint többszálúságot támogató eszköz azt segíti elő, hogy aztán a GDI objektumaidat végül egyetlen szálról kezelhesd, ahová post-oltad a message-t.

Jól látod, nem arra való. Ezzel egy másik szálról megmondod, hogy majd a GUI szál nyúljon hozzá a GDI dolgokhoz, pl a progress bar-hoz. Állításomat igazolja, hogyha a GUI szál foglalt bármi más miatt a hívás pillanatában, akkor a progress bar update nem fog azonnal megtörténni.

De ha úgy meggyőzőbb: amit a másik szálban is írtam, ne higgy nekem. Nyugodtan próbáld ki magad.

Hát nem is hiszek, ugyan miért is kéne bárkinek is hinnie neked?

1. Még semmit nem bizonyítottál (mármint azon kívül, hogy nagy a pofád, és hülyeségeket hordasz össze, ugye)
2. A fenti példa a Microsoft (C) (TM) hivatalos MSDN oldaláról való példakód, ami konkrétan cáfolja az állításod.
3. "GUI szál foglalt bármi más miatt a hívás pillanatában, akkor a progress bar update nem fog azonnal megtörténni." igen, és? Ezzel mégis mit akartál mondani vagy bizonyítani? Ha várakozás van, akkor az már nem többszál lenne szerinted?

Lassan írom, hogy te is megértsd: az állításítodat cáfolja az MSDN-ről származó példakód.
(Post scriptum: nem, csak azért, mert leírod, hogy "állításodat igazolja", attól még nem fogja egy csöppet sem igazolni azt, és már önmagában csak az, hogy ezt hiszed, piszok vicces LOL)

Igen, pont azért van várakozás, mert a GDI-t egyetlen szálról célszerű kezelni. És megvárja, hogy az az egy szál szabad legyen.

Te egy komplett idióta vagy. Csak azért, mert a bankban várni kell, szerinted ebből máris az következik, hogy csak egy ügyfélpult lehet nyitva? Hát nagyon nem.
(Költői kérdés, ne válaszolj, mindenki saját tapasztalatból tudja, hogy nem így van.)

A hasonlatod irreleváns, nem arról van szó, hogyha egy feladatnak várakoznia kell, akkor biztos csak 1 CPU magom van. Senki nem állított ilyet. Alap logika.

Ha értenéd miről lenne szó, azt írtad volna, hogy abban a bankban, ahol egy olyan ügyfélpult van, aki papírra rajzolással foglalkozik, és te papírra akarsz rajzolni, akkor ott meg kell várni, hogy az az egy szabad legyen. A GDI-ban azért kell várni, mert azt az egy szálat meg kell várni, ami az ablakba rajzolást csinálja. Ha ez az UI szál azzal van elfoglalva, hogy egy piros pöttyös labdát rajzol az ablak egyik részébe, akkor a SendMessage használatával küldött progress bar update soha nem fog megtörténni közben, mindig csak akkor, ha már a nagy piros pöttyös labda rajzolása teljesen befejeződött. Ha ez egy multithread UI framework lenne, akkor lenne olyan, hogy ezek egyszerre történnek.

De újra csak ugyanazt tudom mondani, mint egész eddig. Mivel az elképesztő egod miatt nem vagy hajlandó elfogadni a tényt, hogy esetleg mások is érthetnek a programozáshoz, ráadásul anélkül is érthetnek hozzá, hogy egy teljes CV-t mellékelnének neked, és ezért láthatóan az érveimet nem vagy hajlandó megérteni és elfogadni, ezért inkább próbáld ki magad és írd meg, hogy mire jutottál.

nem arról van szó, hogyha egy feladatnak várakoznia kell, akkor biztos csak 1 CPU magom van. Senki nem állított ilyet.

De, TE állítottad ezt szálakkal. CPU magokról konkrétan eddig egyetlen egy nyamvadt szó sem esett ebben a topikban. Féleszű vagy talán?

Menj kisfiam, itt komoly felnőttek beszélgetnek, neked semmi keresnivalód errefelé. Ülj szépen vissza az iskolapadba és legalább annyit tanulj meg, mi a különbség a szálak és CPU magok között.

nem vagy hajlandó elfogadni a tényt, hogy esetleg mások is érthetnek a programozáshoz

Te halál komolyan azt képzeled magadról, hogy értesz a programozáshoz, miközben még a CPU mag és szál fogalmát is kevered? LOL!

ezért inkább próbáld ki magad és írd meg, hogy mire jutottál.

Megtettem (már akkor, amikor ezt a projektet létrehoztam, ha nem esett volna le), és arra jutottam, hogy teljesen hülye vagy. :-D :-D :-D

A CPU mag és a szál ebben a kontextusban majdhogynem mindegy, a lényeg a hasonlatodban, hogy valami, ami a feldolgozást végzi.

De akkor legyen, idézd csak hol állítottam, hogyha egy feladatnak várakoznia kell, akkor csak egyetlen szálam van az egész rendszerben?

Még mindig nem tudsz leszállni a magas lóról, és elengedni azt a képzeteded, hogy nagyságos atyaúristenességedhez nekem ne lenne jogom hozzászólni. Ez egy fórum. Ha ijedős vagy, vagy érvek helyett csak személyeskedni tudsz, akkor ne nyiss topikod. Nem érzed egy kicsit kontraproduktívnak, főleg hogy egyre jobban bonyolódsz bele a tévedéseidbe?

A CPU mag és a szál ebben a kontextusban majdhogynem mindegy

Nono, fiam, kőből talán nem lehet hidat építeni egymagú CPU-n talán nem lehet több szálat futtatni? Hát már hogy ne lehetne. Megint sikerült ékesen bizonyítanod, mennyire nem értesz hozzá, csak rontod itt a levegőt.

idézd csak hol állítottam, hogyha egy feladatnak várakoznia kell, akkor csak egyetlen szálam van az egész rendszerben?

"Igen, pont azért van várakozás, mert a GDI-t egyetlen szálról célszerű kezelni. És megvárja, hogy az az egy szál szabad legyen."
És nem az egész rendszerben, hanem GUI-ra (példádban konkrétan a GDI-re) hány szál van, már megint ferdíteni próbálsz, mert Te is tudod, hogy hülyeségeket beszéltél.

Egy percig sem kell aggódnod, aki csak egy kicsit is ért hozzá, annak már úgyis régen leesett, hogy totál dilettáns vagy. Ülj vissza az iskolapadba, ott a helyed, nem itt.

érvek helyett

Che? Ezidáig minden "érvedről" kiderült, hogy komplett hülyeség, vagy csak kevered az alapfogalmakat.

akkor ne nyiss topikod.

Jól ragzad az finnugrot csak hasoggaja az fülem. Ha nem vagy képes elfogadni, hogy pikk-pakk kiderül, hogy mekkora idióta vagy, akkor ne irogass a fórumba, és nem fog kiderülni.

Nem érzed egy kicsit kontraproduktívnak

Nem. Remekül szórakozom rajtad, közben meg haladok a fejlesztéssel, egy cseppet sem gátol, hogy néha röhögőgörcsöt kapok tőled.

Amit nem vagy képes felfogni, hogy te egy kis senki vagy, aki még semmit nem tett le az asztalra és csak jártatni próbálja a pofáját, de csak hülyét csinál magából vele. Ugyanakkor én teszem a dolgom, fejlesztek és gyakorlati eredményeket produkálok. Miért is kéne, hogy zavarjon, hogy miket próbál itt össze-vissza hordani egy nímand? Nem zavar egy icipici csöppet sem, nem gátol a fejlesztésben :-D

egymagú CPU-n talán nem lehet több szálat futtatni

Egyszerre nem. És ahogy írtam, a banki példád kontextusa volt a hasonlat lényege, ahol nem fogja egy pult időosztásban váltogatni az ügyfeleket, mint egy valódi CPU, ami időosztásban futtat több szálat.

És nem az egész rendszerben, hanem GUI-ra (példádban konkrétan a GDI-re) hány szál van, már megint ferdíteni próbálsz, mert Te is tudod, hogy hülyeségeket beszéltél.

Nem próbálok ferdíteni. Én egész eddig ezt írtam, hogy igen, a UI-hoz egy szál van. Csak, hogy egyértelmű legyen, most nyilván egyetlen ablakról beszélünk, nem arról, hogy különböző processzek különböző ablakai külön UI szálakat használnak. A processzben lehet nyilván több szálad, és ha nem az ablakod UI száláról akarsz valamit, akkor a SendMessage segítségével küldhetsz a UI szálra, hogy csináljon GDI műveletet. És az meg fogja várni, hogy az egyetlen UI szál végezzen az előző műveleteivel. Itt csak magadat kevered ellentmondásba, én az elejétől ugyanazt írom, konzisztensen, már sokadszor, hogy egy UI szál van, amiről kezeled a GDI-t, és erre nem érkezett cáfolat.

minden "érvedről" kiderült, hogy komplett hülyeség, vagy csak kevered az alapfogalmakat.

Nyilvánvaló, hogy legfeljebb másokat, akik ide tévednek tudunk meggyőzni erről-arról, de egymást nem. Az egyetlen dolog, ami dönthetne, hogy az általam javasolt teszteket futtasd le, hogy a saját szemeddel is lásd az igazságot, amit nekem nem akarsz elhinni. De ehhez valamiért papírkutya vagy. Vagy valójában már lefuttattad, csak az eredményt nem akarod megírni ide :D

Jól ragzad az finnugrot csak hasoggaja az fülem

Na, az első valódi érved a topikban, ahol tényleg egy hibát találtál a hozzászólásomban, gratulálok, csak így tovább :)

Remekül szórakozom rajtad, közben meg haladok a fejlesztéssel, egy cseppet sem gátol, hogy néha röhögőgörcsöt kapok tőled.

De érdekes, én is pont ugyanezt teszem. Igazából a nevetés egészséges, úgyhogy ez egy kölcsönösen hasznos tevékenység, ezúttal is köszönöm :)

Amit nem vagy képes felfogni, hogy te egy kis senki vagy, aki még semmit nem tett le az asztalra és csak jártatni próbálja a pofáját, de csak hülyét csinál magából vele. 

Ezt a témát még mindig nem bírod elengedni, hogy kimondottan tuskó paraszt stílusban sértegetsz másokat, anélkül, hogy bármi ismereted is lenne arról, hogy amúgy kik ők, és mit csinálnak. És nem, nem fogok semmit mondani arról, hogy amúgy mit csinálok, mert nyilvánvaló, hogy neked az úgysem elég jó ahhoz, hogy normális stílusban kommunikálj velem.

Én egész eddig ezt írtam, hogy igen, a UI-hoz egy szál van.

Pedig nem is. Tudod, nem az az igazán nagy baj, hogy tévedtél ebben, hanem az, hogy még a tömérdek cáfolat (kódrészlet, MSDN idézet, tutorial linkek, stb.) ellenében sem vagy hajlandó elfogadni a valóságot. Na ez utóbbi már súlyos eset, mondhatni a krónikus téveszme indikátora.

Az egyetlen dolog, ami dönthetne, hogy az általam javasolt teszteket futtasd le,

Ugyan, miért is kéne nekem bármit is csinálnom? Te állítod, rajtad a bizonyítás terhe, futtasd csak szépen le Te és prezentáld Te nekünk az eredményeket! Én már konkrét kódrészleteket másoltam ide, amik cáfolják a hülyeségeid, de még a saját szemednek se hittél. Hogy van egyáltalán bőr a képeden ezek után bármire is kérni engem? Futtasd csak le Te magad és bizonyítsd Te!

anélkül, hogy bármi ismereted is lenne arról, hogy amúgy kik ők, és mit csinálnak.

Még jó, hiszen ezidáig SEMMIT nem voltál képes felmutatni, akkor mégis milyen alapon próbálod számon kérni ezt? Ember, hol élsz Te?

Állásinterjún is ezt mondod, hogy ne tessék foglalkozni a szakmai tapasztalatommal, csak bemondásra tessék elhinni mindent, akkor is, ha konkrét tények cáfolják, de azért vegyenek fel jó fizető állásba! Szerinted melyik idióta venne fel egy ilyen dumával Rogán propagandaminisztériumán kívül?

Pedig nem is. Tudod, nem az az igazán nagy baj

Hadd idézzem, amire már korábban is felhívtam a figyelmedet kb. 10 hozzászólással előbb: "És ha tényleg odafigyelnél, nem írtam, hogy tilos több szálról használni, vagy hogy nem is létezhet ilyen. Csak annyit írtam, hogyan célszerű használni." És te most pont ennek a megerősítését linkelted be. Ügyes. A végén még egyet fogunk érteni :D

Azt hozzátenném, hogy te kanyarítottad a témát abba az irányba a SendMessage-es példáddal, hogy azt próbáljam neked elmagyarázni, hogy ez miért is jelenti azt, hogy egy szálról van kezelve a UI, ha az ajánlott módszerek szerint dolgozol. Nézd meg, hogy mi áll a SendMessage dokumentációjában, egyértelműen ott van, hogyha nem az ablak UI thread-jéről hívod, akkor megvárja, hogy az UI thread szabad legyen, és a tényleges műveletet majd a UI thread fogja megcsinálni. Ez eléggé egyértelműen azt jelenti, hogy egy szálról kezeled a UI-t, igen, pont az a SendMessage példa igazolja ezt, amire hivatkozol. De ezt is már sokadszorra írom le.

Te állítod, rajtad a bizonyítás terhe, futtasd csak szépen le Te és prezentáld Te nekünk az eredményeket

Képzeld, futtattam, ezt le is írtam (még az aszinkron IO részben említettem konkrétan, hogy futtattam is). És az eredmény pont az, amit ott is már az elejétől kezdve állítottam, és amire te nagy arccal replikázol, hogy csak faszság lehet, miszerint nincs annyi OS szál, ahány IO fut egyszerre. Mit másolják be? Kódrészletet, screenshotot, youtube magyarázó videót kínai szinkronnal? Nyilván egyiknek sem hinnél, csak annak, ha saját magad kipróbálod, de lehet, hogy annak se.

milyen alapon próbálod számon kérni ezt

Én nem kérek tőled semmit számon. Én csak egy olyan módszert ajánlottam, amivel objektíven meggyőződhetsz önállóan is arról, hogy kinek is van igaza.

Állásinterjún is ezt mondod, hogy ne tessék foglalkozni a szakmai tapasztalatommal, csak bemondásra tessék elhinni mindent

Állásinterjún nem azt mondom, hogy ne foglalkozzanak a szakmai tapasztalatommal, hanem azt várom, hogy konkrét kérdésekkel mérjék fel a szakmai tapasztalatomat. Jó esetben ugye gyorsan átfutnak a CV-n, és aztán a lényegi rész egy szakmai kérdés-válasz, esetleg kifejtősebb rész. De ugye most nem állásinterjún vagyunk, hanem egy fórumtopikban, ahol a te állításaidra teszek én is állításokat, és ahol semmit nem tesz hozzá vagy vesz el az a dologból, hogy amúgy mi lenne a CV-ben.

Amúgy külön köszönöm azt, hogy ebben a hozzászólásodban kivételesen nem próbáltál jelzőkkel lealacsonyítani, a végén még tényleg eljutunk a kultúrált érveléshez :)

Én egész eddig ezt írtam, hogy igen, a UI-hoz egy szál van.

nem írtam, hogy tilos több szálról használni, vagy hogy nem is létezhet ilyen.

Öcsém, te durvábban tolod, mint a fekete lovag a Gyaloggaloppból.

kivételesen nem próbáltál jelzőkkel lealacsonyítani

Tényleg nem esett le, hogy burkoltan letrolloztalak? Konkrétan fizetett Fidesz propagandistának tituláltalak, és hát szerintem ennél nagyobb sértés ma Magyaroszágon nem létezik.

Igen, így kiemelve a mondatrészeket a környezetükből elég könnyű ellentmondásnak feltünteni. De ugye az egyik arra vonatkozik, hogy hogyan ajánlott, és hogyan működik egy szálon, ha pl. az általad a témába behozott SendMessage van használva, és ami azt teszi könnyen kezelhetővé, hogy biztosítsd, hogy az egyetlen UI szálról történjen minden. A másik meg arról szól, hogyha szeretsz veszélyesen élni, akkor hogyan érd el azt több szálról saját szinkronizációs mechanizmusokkal, hogy a sok szálad közül egy időben egy szál (tehát ismétlem, effektíve egyszerre egy szál egy időben) a GDI objektumodat piszkálni.

 

Konkrétan fizetett Fidesz propagandistának tituláltalak

Hmm. Az ilyen témákat itt kevésbé aktívan követem, ezen tényleg átugrottam :D De ezzel megnyugtattál, hogy helyreállt a világ rendje, és minden rendben van veled.

 

Azért majd ha ráérsz, futtasd le az említett teszteket, most már tényleg kíváncsi lennék az eredményre, hogy nálad vajon mást adnak-e mint nálam.

minden rendben van veled.

Eddig is tudtuk, hogy a baj veled van, ezzel semmi újat nem mondtál...

futtasd le az említett teszteket

Csak miután prezentáltál egy bármilyen egyszálas async megvalósítást és a részletes teszt programodat a TE teszt eredményeiddel! Kisujjamat se kell mozdítanom addig, mert mint minden értelmes ember, én is leszarom a nagypofájú szájhősöket. ;-)

Te állítasz, a bizonyítás terhe a tiéd. Eddig még semmiféle reprodukálható tesztet nem voltál képes letenni az asztalra.

Oké, legyen. Futtasd az alábbi programot nodejs-ben:

const process = require('process'); 
const net = require('net');

const threadCountCommand = process.platform === "win32" ? `(Get-Process -Id ${process.pid}).Threads.Count` : `ps -o thcount ${process.pid}`
console.log(`Observe thread count at program start with command '${threadCountCommand}' and then press Enter`);
process.stdin.once('data', () => {
  process.stdin.unref();
  for (let i = 0; i < 30; ++i)  {
    console.log(`Starting client ${i}`);
    const client = new net.Socket();
    client.on("error", () => {
      console.log(`Client ${i} error`);
    }); 
    const hostIp = "192.168.0.15" // ip address of non existent host so connect takes a while and then fails with timeout
    client.connect(1337, hostIp, () => {
      console.log(`Client ${i} connected`);
    });
  }

  console.log(`Observe thread count while async IOs running with command '${threadCountCommand}'`);
});

A konzolra kiírja az instrukciókat, hogyan kérdezheted le a szálak számát a sok IO művelet elindítása előtt, és miközben fut a sok IO művelet.

Linuxon nodejs v22.5.0 használatával nekem mindkét érték 7 volt (ugye azt említettem, hogy a JavaScript engine használ szálakat, de egész más célokra, nem arra, hogy aszinkron IO-nként elindít egyet), tehát nem indult el új szál, miközben 30 network IO lett elindítva és van folyamatban. Windows-on nodejs v20.10.0 használatával nekem mindkét érték 13 volt, tehát nem indult el egyetlen új szál sem, miközben 30 network IO lett elindítva és van folyamatban.

Szóval csak annyit kell írnod, hogy beismered, hogy tévedtél.

Jellemző a nagyszájú balfaszokra, hogy már kérdést sem értik. Azt hiszed, nincs a nodejs-ben több szál, csak mert a benne futtatott JavaScript szottyod nem látja őket? Mekkora lúzer vagy már!

Lefutattam, egyértelműen tévedtél, egy valag pthread-et indít a nodejs motor hozzá (és ha már itt tartunk, több processzt is). De már megmondtam korábban is, hogy ez a helyzet, csak hát neked még a magyar nyelvű szövegértés sem megy, idézem:

Akkor is, ha a többszálúság csak a motorháztető alatt található és nincs direktben kivezetve a JavaScript API-jára, még akkor is. De egyébként pont a JavaScript async API-járól ORDÍT, hogy többszálú, mit gondolsz, a Promise miért closure és nem kontrollstruktúra?

A helyes válaszhoz a nodejs MOTORjában kellett volna lekérned a pthread-ek számát. De persze minek is magyarázom, jól láthatóan még azzal sem vagy tisztában, mi a különbség az interpreter program és az interpretált program között.

Nyilvánvaló, hogy már eleve a kérdést sem értetted, azért válaszoltál ekkora baromságot... Szerintem menj el inkább építőmunkásnak vagy kertésznek vagy valami, mert a programozáshoz jól láthatóan lövésed sincs. JavaScript kódot összekopipasztázni bármelyik filippínó migráncs is képes.

Gondoltam, hogy valami totál faszságot fogsz válaszolni.

Próbáltad értelmezni, hogy mit csinál ez a program? Ő nem kérdezi le a szálak számát, azt rád bízza, hogy kérdezd le külsőleg, mondjuk ps paranccsal, és ehhez ír ki segéd utasítást. Így külsőleg szemlélve tudod megnézni, hogy hány szálad van. És pont a hogy a nodejs motorjában, a futó nodejs processzben tudod lekérdezni a szálak számát, az outputra kiírt utasítás segítségével. Nem tudom mit kevered ide az interpretált program és interpreter közti különbséget, totál irreleváns. Egyetlen processz van, a nodejs, amiben fut ez a program, és ami kezeli a JavaScript-et, az IO-t, mindent. És annak a szálainak a számát kérdezzük le. Két ponton: mielőtt elindítod a sok IO-t, és miután már elindultak. És meglepetés, a szám ugyanannyi. Tehát nem indul új szál, amikor IO-t indítunk.

És igen, írtam, hogy a JavaScript engine indít szálakat, de nem azért, hogy aszinkron IO-t indítson. Tehát nagyon ügyesen felfedezted, hogy amúgy indulnak szálak. De nem azért, hogy minden egyes aszinkron IO egy külön szálon fusson.

De egyébként pont a JavaScript async API-járól ORDÍT, hogy többszálú

Nem, nem ordít.

Ezeket is már korábban leírtam, de egyszerűen sötéthülye vagy hozzá, hogy bármit is megérts ebből a témából. Nem hiszem, hogy van értelme sokkal tovább ragozni. Csak megismételni tudom: "Olyan vagy az aszinkron IO kapcsán, mint az egyszerű bácsi, aki csak áll az állatkertben, és ismételgeti a zsiráfra, hogy ilyen állat márpedig nincs.". Ráadásul most már tényleg eléd raktam a zsiráfot, de baszki még mindig nem hiszed el, hogy létezik.

Ő nem kérdezi le a szálak számát

Lófaszt nem, a példád konkrétan az interpretált programod processz id-jéhez tartozó, és csak az ahhoz tartozó szálakat kéri le, ezért kapsz hibás eredményt. Mondtam, nem tudod, mi a különbség az interpreter és interpretált között, azért vétettél ilyen hibát (vagy pedig csak fel sem fogtad, mit kopipasztáztál).

Nem, nem ordít

Dehogynem, csak te egy nagyszájú tanulatlan tuskó vagy, zéró programozói vénával, azért nem vetted észre.

Minden closure valójában egy új szál, máskülönben a párhuzamos futtatás nem is lenne lehetséges, a példádból:

    // ez itt lenni NODEJS SZÁL #1
    client.connect(1337, hostIp, () => {
      // ez itt lenni NODEJS SZÁL #2, futni egyszerre SZÁL #1 mellett párhuzamosan
      console.log(`Client ${i} connected`);
      // SZÁL #2 itt most terminálni, SZÁL #1-től függetlenül, az futni tovább
    });
    // ez itt lenni továbbra is NODEJS SZÁL #1, futni SZÁL #2-től függetlenül

Megmondtam, csupán csak azért, mert a JavaScript szottyod nem éri el szálként, nem azt jelenti, hogy ne lenne szál a motorháztető alatt.

Nem, ezek nem külön szálak. És nem futnak párhuzamosan. Amikor valamilyen esemény bekövetkezik, pl. egy IO sikerre vagy hibára fut, akkor az adott callback hívódik meg azon az egyetlen szálon. Ha az az egyetlen szál egy while (true); ciklusban ragadt épp, mert a korábbi callback-ed hibás, akkor nem hívódik meg az új callback.

És hozzátenném, hogy ez nagyon-nagyon alap JavaScript működés, így fut a browserben és a nodejs-ben is.

Nem, ezek nem külön szálak. És nem futnak párhuzamosan.

Tehát szerinted a főciklus, az on error closure és a connected closure nem párhuzamosan fut? Ülj csak szépen vissza az iskolapadba: Closures, Understanding Closures. Mondtam én, nem is tudod, miről beszélsz.

Próbáld csak ki, hogy ne pár mikroszekundum életidejű closure-jeid legyenek, hanem pár percesek, és még ps sem fog kelleni, hogy lásd, hülyeséget beszélsz. Vagy próbáld csak ki ezt a példát, nincs benne szálkezelés (JS szinten), se semmi, és mondd meg, práhuzamosan fut-é a főprogrammal:

setTimeout(function(){ console.log("Lenni nem main szál"); }, 100);
console.log("Lenni main szál");

Nézz már utána a JavaScript event loopnak.

Ja, és a closure mint fogalom teljesen független a többszálúságtól. A callbacke-et körülvevő változók capture-eléséhez van köze, a részletekért ajánlom a saját linkedet értelmezni.

Amit írtál példa, az pont arról szól, hogy mikroszekundum ideig tartó callback-jeid vannak. Nyugodtan próbáld ki, hogy a fő szálon egy olyan ciklust futtatsz, ami mondjuk két másodpercig pörög aktívan. A setTimeout-os callback-ed nem fog meghívódni, csak két másodperc múlva.

Ja, és a closure mint fogalom teljesen független a többszálúságtól.

Mondod te (persze hibásan), miközben én meg konkrétan belinkeltem a specifikációt, ami direktben cáfol. Ekkora lúzert!

Ha még azt sem látod, ami a specben kerek perec le van írva, és amit még a saját példaprogramod empirikusan is igazol (elég egy várakozás a closure-ökbe ehhez), akkor tényleg menthetetlen vagy, tegyél egy szívességet a HUP közösségének és menj egy kertésznek vagy építőmunkásnak, mert A PROGRAMOZÁS NEM NEKED VALÓ.

Uff, ennél többet nincs mondanom. Öszintén sajnálom a munkáltatód, már ha egyáltalán IT területel dolgozol és meló helyett trollkodsz itt. Ha, mint sejtem, Rogán propagandaminisztériumának fizett trollja vagy, akkor meg üzenem, eljövünk még értetek!

belinkeltem a specifikációt

És el is olvastad? Mert úgy látszik, hogy nem. Vagy nem érted.

De hogy tiszta legyen, íme a következő program, sokkal egyszerűbb, hogy megértsd a JavaScript működésének az alapjait:

function log(s) { console.log(new Date(), s); };
setTimeout(function(){ log("Lenni nem main szál"); }, 100);
log("main szál 1");
const t0 = Date.now();
while (Date.now() - t0 < 2000);
log("main szál 2");

És a kimenet:

2024-07-20T10:04:06.726Z main szál 1
2024-07-20T10:04:08.735Z main szál 2
2024-07-20T10:04:08.736Z Lenni nem main szál

Ebből vajon mit szűrsz le? :D

Ebből vajon mit szűrsz le?

Hát azt, hogy nem értesz hozzá.

Tehát nem indul új szál, amikor IO-t indítunk.

Dehogynem, csak a példádban egyelen console.log hívás van bennük, így be is fejeződtek, mire a második ps-t kiadod. Mondtam már, tegyél bele várakozást, hogy pár percig fussanak, és meglátod, faszságokat beszélsz.

De tudod mit? Jó, tegyük fel, csak a vicc kedvéért, hogy valóban csak egyetlen szállal operál, és a főciklus nem halad tovább, amíg a connect() le nem fut (de, továbbhalad, de azért most tegyük fel, hogy valóban úgy van, ahogy állítod). Ebben az esetben hol van itt az aszinkron IO? Ha blokkolódik a programod az IO művelet befejeztéig, akkor az - definíció szerint - NEM aszinkron.

Szóval teljesen mindegy, melyik az igaz, mivel mindkét esetben tévedtél, és még mindig nem voltál képes példát mutatni aszinkron működésre egyetlen szállal (nem is fogsz soha, mert nem lehetséges).

Hát azt, hogy nem értesz hozzá.

Akkor magyarázd már meg, hogyha szerinted ez többszálú, akkor miért a "main 2" után jön a "nem main"?

 

Dehogynem, csak a példádban egyelen console.log hívás van bennük, így be is fejeződtek, mire a második ps-t kiadod

Te itt most egy kicsit kevered, hogy azért kéne-e új szálnak lennie, mert folyamatban van az aszinkron IO, vagy pedig azért mert befejeződött az aszinkron IO, és fut a callback. De segítek, egyik esetben sem lesz új szál. Nyugodtan próbáld ki, hogy busy loop-okat raksz a callback-ekbe. De ha nagyon szeretnéd tovább égetni magad, megteszem neked, és bemásolom ide az eredményt.

Ebben az esetben hol van itt az aszinkron IO? Ha blokkolódik a programod az IO művelet befejeztéig, akkor az - definíció szerint - NEM aszinkron

Nem blokkolódik a program. Ahogy elindult az első connect (aszinkron módon), utána indul a második és így tovább. És a 30. után is még csinálhatnék akármit, az aszinkron IO megtörténik a háttérben, szál nélkül. Ez pont az, hogy nem blokkol a program. És amikor egy IO befejeződik, sikeresen vagy sikertelenül, és éppen nem dolgozik a JavaScript egyetlen szála, akkor a sikerhez vagy a sikertelenséghez tartozó callback majd meghívódik. Ha pár millisec-ig tart a callback, akkor hamar felszabadul a JavaScript egyetlen szála, és kész arra, hogy a következő IO befejezés callback-jét majd futtassa. Ha sokáig tart, mert egy busy loop-ot rakok a callback-be, akkor a következő callback nem hívódik meg azonnal.

Nem blokkolódik a program.

Hanem?

És amikor egy IO befejeződik, sikeresen vagy sikertelenül, és éppen nem dolgozik a JavaScript egyetlen szála, akkor a sikerhez vagy a sikertelenséghez tartozó callback majd meghívódik.

Szóval blokkolódik a hívás, amíg az IO nem végez?

Ha sokáig tart, mert egy busy loop-ot rakok a callback-be, akkor a következő callback nem hívódik meg azonnal.

Tehát mégsem aszinkron? Nem azt mondtad az előbb, hogy nem blokkolódik?

megtörténik a háttérben, szál nélkül.

Hogyan? A különböző callbackek szerinted nem szálak? És ha a háttérben történik, akkor miért kell várnia az egyik callbacknek a másikra?

Össze-vissza beszélsz és kevered a fogalmakat, már annyira elvesztél a saját hazugságaidban, hogy azt sem tudod, mi is az az aszinkron meg mi is az a szál. LOL.

Nem blokkolódik a program.

Hanem?

Ha blokkolódna az első connect után, akkor a második connect nem hívódna meg, amíg az első nem fut sikerre vagy hibára. De nem blokkolódik. Ez az aszinkron IO.

Ha sokáig tart, mert egy busy loop-ot rakok a callback-be, akkor a következő callback nem hívódik meg azonnal.

Tehát mégsem aszinkron? Nem azt mondtad az előbb, hogy nem blokkolódik?

A busy loop az nem IO. Az pont hogy CPU művelet, és az blokkol. Mivel hogy egy szálon megy a JavaScript.

 A különböző callbackek szerinted nem szálak?

Nem, nem szálak. A callback-ek azok callback-ek, magyarul függvények, amik majd végrehajtódnak később. Az egyetlen JavaScript szálon.

És ha a háttérben történik, akkor miért kell várnia az egyik callbacknek a másikra?

Az egyik callbacknek akkor kell várnia másikra, ha a másik callback CPU művelet miatt blokkolva van. IO miatt sosincs blokkolva semmi, ez az aszinkron IO lényege.

Össze-vissza beszélsz és kevered a fogalmakat

Ezt éppenséggel te teszed. Nézz már utána ezeknek valahol, ahol meg is érted. Az látszik, hogy nekem nem hiszel.

Egyáltalán nincs szó veszekedésről, azon szórakozom csupán, hogy önellentmondásokba kergettem a trollunkat.

Ha veszekedésnek tűnt volna, akkor elnézést, nem akartam másokat zavarni vele, csak őt szándékozom az őrület és önmarcangolás legmélyebb és legsötétebb bugyraiba kergetni, mert megérdemli azok után, amilyen nagy pofával beszélt, miközben semmit sem tett még le az asztalra. Mondanám, hogy a cél az, hogy tanuljon belőle, de sajnos úgysem fog.

eltekintve attól, melyikőtöknek van igaza, a stílusotokat összevetve éppenséggel te tűnsz ideggyenge, önmagától elszállt, végtelenül önelégült, nagypofájú agresszornak. bármekkora is a tudásod, rendkívül ellenszenves a viselkedésed. jöhet a fröcsögés ide is, vagy hogy ez a "mesterterv" része.

Nem blokkolódik a program.

Az egyik callbacknek akkor kell várnia másikra, ha a másik callback CPU művelet miatt blokkolva van.

Akkor most mégis van blokkolódás?

IO miatt sosincs blokkolva semmi, ez az aszinkron IO lényege.

És ha sokáig tart a connect, az miért más, mintha a clojure-ben van busy loop? Melyik esetben folytatódik a főszál futása, melyiknél nem? Honnan tudja az az egy JavaScript szál, hogy melyik eset forog fenn egyáltalán?

A busy loop az nem IO. Az pont hogy CPU művelet, és az blokkol. Mivel hogy egy szálon megy a JavaScript.

Ez esetben mit értettél az alatt, hogy "megtörténik a háttérben"? Mi az a háttérben?

IO miatt sosincs blokkolva semmi

Hogyhogy? De azt mondtad, hogy a callback várakozik, amíg az IO nem végez. És azt is mondtad, hogy a callback futása alatt nem folytatódhat más. Mivel egy JavaScript szál van, így nyilván az a callbacket futtatja, tehát a főszál sem futhat addig, amíg az nem végez, igaz?

Nézz már utána ezeknek valahol, ahol meg is érted.

Téged kérdeztelek. Kérlek magyarázd el, mit értesz azon, hogy a "háttérben megtörténik", ha csak egyetlen egy szál van.

És ha sokáig tart a connect, az miért más, mintha a clojure-ben van busy loop? Melyik esetben folytatódik a főszál futása, melyiknél nem? Honnan tudja az az egy JavaScript szál, hogy melyik eset forog fenn egyáltalán?

A connect azért más, mert az egy aszinkron IO művelet. Belül az történik, hogy megkéred az oprendszert, hogy csatlakozzon egy host-hoz, de egyből visszatér a system call, a szálad fut tovább. És ezáltal a JavaScript szálad is fut tovább. Ha utána kiírod, hogy "Hello", akkor kírja hogy "Hello", nem várja meg, hogy connect befejeződjön hálózati szinten. Aztán eljut a JavaScript odáig, hogy nincs mit végrehajtani, mert vagy az aktuális callback utolsó soráig elért, vagy a főprogram utolsó soráig (ez utóbbi esetben ha van pending IO, akkor még nem lép ki). Ekkor az egyetlen szál átmegy egy olyan állapotba, hogy várakozik arra, hogy bármely korábban indított IO, vagy setTimeout vagy bármi hibára vagy sikerre fusson. És akkor annak a callback-jét kezdi el végrehajtani.

Ezzel szemben, ha busy loop van, akkor az konkrétan valamilyen JavaScript sorokat hajt végre a főprogramban vagy egy callback-ben, az egyik után a következőt, mondjuk ciklusban. És ez nem megszakítható ezen a JavaScript világon belül (más processzekkel nyilván lehet time share-ben). És a következő IO vagy setTimeout vagy akármi befejeződésekor annak a callbackje ilyenkor nem tud elindulni ezért egy queue-ba kerül. Ha a JavaScript elért az aktuális callback utolsó soráig, akkor kezdi el elindítani a következőt.

Ez esetben mit értettél az alatt, hogy "megtörténik a háttérben"? Mi az a háttérben?

Ez eléggé el van absztrahálva az oprendszer által. De a "háttérben" alapvetően azt jelenti, hogy nincs közben blokkolva egy szál, sehol, még a kernelben sem. Mert az aszinkron IO esetén olyan hívások vannak, hogy kezdd el az IO-t, vagy pedig várjunk arra, hogy a megkezdett IO-k közül valamelyik befejeződjön (ez az állapot, amikor a JavaScript következő callback elkezdésére várakozik). És a kettő közt nem kell várnia a szálnak bármi mást csinálhat. Belül a kernelben az egész lánc végig aszinkron, tehát egészen a hardver interruptok szintjéig úgy van ez kezelve szinte mindig, hogy nincs blokkolás: elindít egy hardver IO-t, és aztán majd valamikor jön egy interrupt, ami jelzi hogy befejeződött az IO. És akkor indul visszafelé alulról az aszinkron IO befejeződését jelző hívási lánc, és jut el oda, hogy az IO befejeződésére várakozó user módú programot értesíti. És akkor a JavaScript elkezdi az adott IO befejeződéséhez tartozó callback-et végrehajtani. Ha a user módú program még nem jutott el oda, hogy IO befejeződésre várjon, mert busy loop-ban van, akkor a kernel addig félreteszi a befejeződött IO adatcsomagját, és majd akkor adja oda a user módú programnak, ha az elkezd IO befejeződésre várni.

Hogyhogy? De azt mondtad, hogy a callback várakozik. 

A callback nem IO miatt várakozik. Akkor várakozik, ha az előző callback busy loop-ban van.

És azt is mondtad, hogy a callback futása alatt nem folytatódhat más. Mivel egy szál van, így nyilván az a callbacket futtatja, tehát a főszál sem futhat addig, igaz?

Főszál helyett használjunk főprogram elnevezést. A főprogram mindig elfut a végéig, és ha közben volt elindítva bármi IO vagy setTimeout, akkor ott várakozó álláspontra kerül, és megvárja, hogy ezek közül valamelyik befejeződjön. Ha korábban befejeződik egy setTimout vagy egy IO, mint hogy a főprogram elérjen a végére, akkor annak a callback-je várni fog. Ezt láttad a korábbi setTimeout-os minimál példában. És ha ez kész, akkor az éppen befejeződött IO vagy setTimeout callbackje hajtódik végre. Ugyanazon a szálon, mint a főprogram.

A connect azért más, mert az egy aszinkron IO művelet. Belül az történik, hogy megkéred az oprendszert, hogy csatlakozzon egy host-hoz, de egyből visszatér a system call, a szálad fut tovább.

Hogyan? A BSD socket connect() hívása blokkoló, szinkron hívás (mint ahogy az összes többi POSIX IO múvelet is). Nem tér az a syscall vissza egyáltalán, amíg a kapcsolat kialakítása folyamatban van. Hogy lesz ebből aszinkron NodeJS connect, ha, idézem: "a JavaScript engine indít szálakat, de nem azért, hogy aszinkron IO-t indítson"?

Mitől válik a blokkoló syscall nem blokkolóvá, ha csak egyetlen szálad van?

az konkrétan valamilyen JavaScript sorokat hajt végre a főprogramban vagy egy callback-ben

Tehát a főszál (sem másik callback) nem futhat addig, míg a connectet lekezelő callback nem végez? Akkor hogy fog olvasni az egyik callback a megnyitott csatornából időben, ha közben egy másik callback busy loopban van épp? Vagy, ha nem képes ilyenkor olvasni a csatornából, mert várakozik, akkor az hol aszinkron?

És a következő IO vagy setTimeout vagy akármi befejeződésekor annak a callbackje ilyenkor nem tud elindulni ezért egy queue-ba kerül. Ha a JavaScript elért az aktuális callback utolsó soráig, akkor kezdi el elindítani a következőt.

Dehát azt mondtad, a callbackek nem szálak, akkor hogyan kerülhetnének egy queue-ba későbbi futásra? Mi is kerül a queue-ba pontosan? Csak nem egy főszáltól független utasításszámló (azaz magyarul egy másik szál)?

De a "háttérben" alapvetően azt jelenti, hogy nincs közben blokkolva egy szál, sehol, még a kernelben sem.

Kifejtenéd ezt kérlek? Mi történik a hívó szállal a kernelben a connect() rendszerhívás közben, miután kiment SYN, de nem érkezett még meg a SYN+ACK csomag? Ha nem blokkolódik, akkor mit csinál addig?

A callback nem IO miatt várakozik. Akkor várakozik, ha az előző callback busy loop-ban van.

Honnan tudja a főszál, hogy a callback fut vagy még a connect-re várakozik? Hogy tér el a főszál futásának működése e két esetben? És mi történik akkor, ha a főszál busy loop-ban várakozik, és pont végez egy IO, hogy hívódik meg akkor a callbackje? Vagy nem hívódik meg, azaz nem aszinkron?

Főszál helyett használjunk főprogram elnevezést.

Miért? Mi a baj a főszál elnevezéssel?

A főprogram mindig elfut a végéig, és ha közben volt elindítva bármi IO vagy setTimeout, akkor ott várakozó álláspontra kerül, és megvárja, hogy ezek közül valamelyik befejeződjön.

Hogyan kerül várakozó álláspontra, ha nincs blokkolódás? Vagy mégiscsak blokkolódik?

Ha korábban befejeződik egy setTimout vagy egy IO, mint hogy a főprogram elérjen a végére, akkor annak a callback-je várni fog.

Tehát mégiscsak tovább blokkolódik a főszál lefutásának végéig, azaz nem is aszinkron? Hogy működhet egyáltalán úgy a setTimeout, ha a callbackje nem is hívódik meg a megadott idő után, hanem majd csak miután végzett a főszál meg összes többi előtte beütemezett callback? A specifikáció szerint a megadott idő után (adott hibahatáron belül) fut le a callback, nem pedig majd egyszer valamikor. Hogy is van ez?

És mi van ha setTimeout-ot átírod setInterval-ra? Akkor mikor végez a program? Soha?

Hogyan? A BSD socket connect()

Mitől válik a blokkoló syscall nem blokkolóvá, ha csak egyetlen szálad van?

A connect nem fog blokkolni, ha előtte a socket-et SOCK_NONBLOCK opcióval hozod létre.

Tehát a főszál (sem másik callback) nem futhat addig, míg a connectet lekezelő callback nem végez? Akkor hogy fog olvasni az egyik callback a megnyitott csatornából időben, ha közben egy másik callback busy loopban van épp? Vagy, ha nem képes ilyenkor olvasni a csatornából, mert várakozik, akkor az hol aszinkron?

Tipikusan addig a kernel tárolja a beérkezett adatcsomagot. Amikor a user módú program oda jut, akkor kéri a kernelt, hogy a befejezett IO vagy timeout műveletek közül adjon vissza valami eredményt.

Dehát azt mondtad, a callbackek nem szálak, akkor hogyan kerülhetnének egy queue-ba későbbi futásra? Mi is kerül a queue-ba pontosan? Csak nem egy főszáltól független utasításszámló (azaz magyarul egy másik szál)?

A callback-et úgy képzeld el, mint egy adatstruktúra (kb. mint egy function pointer és még egyéb adatok). És ezek kerülnek egy queue-ba, hogy majd végre kell hajtani. A főszálon.

Kifejtenéd ezt kérlek? Mi történik a hívó szállal a kernelben, miután kiment SYN, de nem érkezett még meg a SYN+ACK csomag? Ha nem blokkolódik, akkor mit csinál addig?

Ha blokkoló connect-et használtál, akkor sleep-be teszi a user módú szálat. És majd felébreszti, ha befejeződött az IO. Ha nem blokkoló connect-et használtál, akkor ugye fut tovább a user módú szál a további utasításaival.

Honnan tudja a főszál, hogy a callback fut vagy még a connect-re várakozik? Hogy tér el a főszál futásának működése e két esetben?

Ezt nem kell külön "tudni". Egy szál van, és az vagy JavaScript utasításokat hajt végre, tehát magát a callback-et. Vagy ha azokkal már végzett, akkor pedig a JavaScript engine várakozik az IO vagy timeout-ok közül valamelyiknek a befejezésére. Ha valamelyik befejeződött, futtatja a következő callback-et. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop

Miért? Mi a baj a főszál elnevezéssel?

Hogy félrevezető, mert a JavaScript programozási modelljében egyetlen szál van.

Hogyan kerül várakozó álláspontra, ha nincs blokkolódás? Vagy mégiscsak blokkolódik, míg az IO nem fejeződik be, azaz nem aszinkron?

Ha már nincs mit számolni CPU-n, mert a főprogram összes JavaScript-jét végrehajtotta, akkor igen, várni fog, hogy valami IO befejeződjön, amit a főprogram korábban elindított. Ezt nevezheted blokkolásnak, de azért félrevezető, mert a blokkolást akkor szokták használni, ha amúgy mást is tudnál csinálni. De ilyenkor nincs már teendő, csak vársz egy IO-ra.

Tehát mégiscsak tovább blokkolódik a főszál lefutásának végéig, azaz nem is aszinkron?

Az IO aszinkron. A JavaScript utasítások végrehajtása nem. Az egymás utáni lépésekben történik. És ez akkor "blokkol" valamit, ha a következő callback bekövetkezne. Ez ugye akkor van, ha a főprogram vagy valamelyik callback még továbbra is JavaScript utasításokat hajt végre.

Hogy működhet egyáltalán úgy a setTimeout, ha a callbackje nem is hívódik meg a megadott idő után, hanem majd csak miután végzett a főszál meg összes többi előtte beütemezett callback? A specifikáció szerint a megadott idő után (adott hibahatáron belül) fut le a callback, nem pedig majd egyszer valamikor.

Ez tévedés. Ha közben a főszál foglalt valamivel, akkor a timeout késni fog. Nézd meg a korábban mellékelt setTimeout-os példaprogramot, aminek a kimenetét is mellékeltem. És nyugodtan futtasd le magad is. És nézd meg a specifikációt is: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for…

Hogy is van ez? És mi van ha setTimeout helyett átírod setInterval-ra? Akkor mikor végez a program? Soha?

Remek meglátás, soha nem végez a program. Próbáld ki:

function log(s) { console.log(new Date(), s); };
setInterval(function(){ log("interval"); }, 100);
log("főprogram");

A connect nem fog blokkolni, ha előtte a socket-et SOCK_NONBLOCK opcióval hozod létre.

De fog, mert az csak a read/write-ra vonatkozik, amiket többször is hívhatsz. De tegyük fel a vicc kedvéért, hogy így van, hogy értesül akkor a js motor róla, hogy végzett a connect rendszerhívás? Másold ide kérlek a man page-ből azt a részt, ami a callback indító mechanizmushoz szolgál.

Tipikusan addig a kernel tárolja a beérkezett adatcsomagot.

Nyilván, a kérdés nem ez volt, hanem az, hogy mit csinál a szál közben, ha állítólag még kernel szinten sincs blokkolt szál?

Amikor a user módú program oda jut, akkor kéri a kernelt,

"Oda jut"? Hogyan? Mikor és hogy jut oda, ha az egy szem szálán épp a fő Javascript szál futtatásával van elfoglalva és nem is kéri a kernel-t? (Állításod szerint a kernel kérése már megtörtént és egyből vissza is tért). Másold ide kérlek a man page-ből azt a részt, ami a callback indító mechanizmushoz szolgál.

A callback-et úgy képzeld el, mint egy adatstruktúra (kb. mint egy function pointer és még egyéb adatok).

Na és mi a "function pointer", ha nem egy utasításszámláló érték? Az a bajod, hogy sejtelmed sincs az alapfogalmakról és még azt is összekevered, mi a multithreading és a multitasking.

Ha blokkoló connect-et használtál, akkor sleep-be teszi a user módú szálat.

Na de a) azt mondtad nincs blokkolás, b) nem történt alarm rendszerhívás se. (A sleep LIBC FUNKCIÓ által kiadott ALARM rendszerhívás hatására bekövetkező timer-based blocking és az IO blocking két hullára különböző dolog, de még ezt is sikerült totál összekeverted, gratulálok!).

Ha nem blokkoló connect-et használtál, akkor ugye fut tovább a user módú szál a további utasításaival.

Na de akkor hogy és miként értesül az IO művelet befejeztéről? A connect-et nem hívogathatod többször, mint a read-et/write-ot. Másold ide kérlek a man page-ből azt a részt, ami a callback indító mechanizmushoz szolgál.

Ezt nem kell külön "tudni". Egy szál van, és az vagy JavaScript utasításokat hajt végre, tehát magát a callback-et.

Lassan a testtel, hapsikám! Az az egyetlen JavaScript szál épp a főszálat hajta végre! Honnan is tudja egész pontosan, hogy most már a callbecket kellene futtatnia helyette?

Hogy félrevezető, mert a JavaScript programozási modelljében egyetlen szál van.

Már az AI is megmondta neked, hogy hülye vagy, több szál van. Még mindig nem vagy képes felfogni, hogy csak azért, mert a sok-sok szál nincs kivezetve a JavaScript API-ra, és az csak egyet lát, attól még a motorháztető alatt bizony mind-mind ott vannak a szálak.

Ha már nincs mit számolni CPU-n, mert a főprogram összes JavaScript-jét végrehajtotta, akkor igen, várni fog, hogy valami IO befejeződjön, amit a főprogram korábban elindított.

Na de azt mondtad, nincs blokkolódás....

Ezt nevezheted blokkolásnak, de azért félrevezető, mert a blokkolást akkor szokták használni, ha amúgy mást is tudnál csinálni.

Citation required! És ellentmond a fenti mondatodnak. Gyengébbek kedvéért a helyes definíció: A blokkolás azt jelenti, hogy ez a szál nem futhat, mert kénytelen várakozni erőforrásra, és ennek az égadta világon semmi köze sincs ahhoz, hogy van-e esetleg még más szál és hogy azok épp milyen státuszúak (illetve még az sem számít, hogy milyen erőforrásra is várakozik épp, lehet az IO művelet, CPU, időzítő stb.). A blokkolt szál fogalmában NEM szerepel többi szál.

És ez akkor "blokkol" valamit, ha a következő callback bekövetkezne. Ez ugye akkor van, ha a főprogram vagy valamelyik callback még továbbra is JavaScript utasításokat hajt végre.

Na de akkor ez nem aszinkron.

Ha közben a főszál foglalt valamivel, akkor a timeout késni fog.

Nem ezt mondtad, hanem hogy egyáltalán nem fog futni, amíg a főprogram és a beütemezett callbackek teljesen be nem fejeződtek. Ez kurvára nem ugyanaz.

És nyugodtan futtasd le magad is.

Kipróbáltam Firefox, Chromium és még Netsurf (+libjavascript) böngészőkkel is, nincs késés (a megadott hibahatáron túl), a setTimeout szál párhuzamosan fut a fő szállal.

azt a részt, ami a callback indító mechanizmushoz szolgál

Na de akkor hogy és miként értesül az IO művelet befejeztéről?

Ahogy már korábban is említettem, a select-nek vannak modern alternatívái, pl. az epoll. Úgy építed fel az epoll struktúrádat, hogy benne legyen az összes async IO-val elindított műveletedhez tartozó descriptor. És akkor epoll_wait meghívásával megkapod, hogy valamelyiken teljesült az IO, és akkor mehet a callback végrehajtása. És az epoll_wait működik a connect-re is.

"Oda jut"? Hogyan? Mikor és hogy jut oda?

Vagy aktívan kódot hajt végre, vagy ha azzal végzett, akkor "oda jut" és epoll_wait -et hív. És aztán folytatja a befejeződött IO-hoz tartozó callback végrehajtásával.

sok-sok szál nincs kivezetve a JavaScript API-ra, és az csak egyet lát, attól még a motorháztető alatt bizony mind-mind ott vannak a szálak.

Én pont ezt értem az alatt, hogy JavaScript programozási modellje egy szálú, hogy ami a JavaScript programozó lát, az egyszálú működés. És igen, amúgy vannak egyéb szálak a motorháztető alatt.

Lassan a testtel, hapsikám! Az az egyetlen JavaScript szál épp a főszálat hajta végre! Honnan is tudja egész pontosan, hogy most már a callbecket kellene futtatnia helyette?

Az JavaScript-et végrehajtó egyetlen főszál először a főprogramot hajtja végre, aztán vár arra, hogy egy IO befejeződjön, és akkor az ahhoz tartozó callback-et.

hogy egyáltalán nem fog futni, amíg 

Ez nem azt jelenti, hogy akkor késni fog a timeout?

Kipróbáltam Firefox, Chromium és még Netsurf (+libjavascript) böngészőkkel is, nincs késés (a megadott hibahatáron túl), a setTimeout szál párhuzamosan fut a fő szállal.

Erre át tudod küldeni a kódot, hogy te mivel próbáltad ezt ki? Szeretném megérteni, hogy mire gondolsz, remélem meg tudod tenni mindannyiunk okulására.

Én erre gondoltam, pl. Chrome-ban vagy Firefox-ban futtatva:

<script>
function log(s) { console.log(new Date(), s); };
setTimeout(function(){ log("Lenni nem main szál"); }, 100);
log("main szál 1");
const t0 = Date.now();
while (Date.now() - t0 < 2000);
log("main szál 2");
</script>

És nálam ez a kimenete

Sun Jul 21 2024 09:19:09 GMT+0200 (Central European Summer Time) 'main szál 1'
Sun Jul 21 2024 09:19:11 GMT+0200 (Central European Summer Time) 'main szál 2'
Sun Jul 21 2024 09:19:11 GMT+0200 (Central European Summer Time) 'Lenni nem main szál'

Mit görcsölsz, amikor már beismerted a tévedésed?

ha azzal végzett, akkor "oda jut" és epoll_wait -et hív.

Nem így működik. De még ha így is működne, na akkor századjára is leírom, hogy az aktív pollozás az a MULTIPLEXELÉS, te nagyon sötét.

Én pont ezt értem az alatt, hogy JavaScript programozási modellje egy szálú, hogy ami a JavaScript programozó lát, az egyszálú működés.

Ezt senki nem kérdezte, senkit nem érdekel, hogy a programozó számára milyen API-t nyújt. A kérdés kifejezetten az volt, hogyha a motor egyszálú lenne (de mint tudjuk nem az), akkor hogy lenne képes megvalósítani az aszinkron IO-t.
Na ezért mondtam, hogy Te még azt sem vagy képes felfogni, hogy mi a különbség az interpreter és az interpretált között. Már megint az utóbbiról próbálsz hadoválni, balfaszkám, miközben a kérdés az előbbire vonatkozik.

És igen, amúgy vannak egyéb szálak a motorháztető alatt.

Nemcsak akármilyen egyéb szálak. Az AI válaszát idézve (kiemelés tőlem): "A Node.js és a V8 motor szálkezelése összetett folyamat, amely az asszinkron I/O hatékony kezelését célozza meg." Azaz nemcsak egyszerűen többszálú, hanem kifezetten az aszinkron IO-t kezelik azok a motorháztető alatti szálak. De persze a te értelmi színvonaladon ezt képtelen vagy felfogni, mert a hozzád hasonló kopipészt huszárok az egészből maximum csak a JS API-t látják.

Az JavaScript-et végrehajtó egyetlen főszál először a főprogramot hajtja végre, aztán vár arra, hogy egy IO befejeződjön

Amit itt leírtál, az minden, csak nem aszinkron működés.

A JS működött egyetlen HW szált biztosító gépeket is, és ha elindítod egy egyetlen HW szálra korlátozott virtuális gépben, akkor ma is működik.

A másik kommentben mutattam példát arra, hogy egyetlen szálon - úgy, hogy még az OS-ben sincsen másik szál, még interrupt sem - meg lehet valósítani a JS aszinkron IO modelljét.

Lehetetlenség jó helyre küldeni
asch V | 2024. 07. 22., h – 12:45 üzenetére akartam küldeni

+1
Nem tudom miről szól ez a vita, de a js az szerintem 1 szálon fut csak a visszahívások ütemezése miatt tűnik úgy mintha többszálú lenne. Legalábbis addig míg nem használunk valamilyen worker -t, de ott meg kell írni az api -t is hozzá.
ez itt teljes baromság:
 

function log(s) { console.log(new Date(), s); };
setTimeout(function(){ log("Lenni nem main szál"); }, 100);
log("main szál 1");
const t0 = Date.now();
while (Date.now() - t0 < 2000);
log("main szál 2");

Ez egy szálon fut. 

>konkrétan belinkeltem a specifikációt

A specifikációt megnyitottam és rákerestem a "thread" szóra: zéró találat :-)

A másik linken belépést kér, ilyen elvből nem használok, úgyhogy az a link vitában invalid.

Egyébként a JS specifikációja pontosan az, hogy ezek mind sorban egymás után futnak le, a párhuzamosságot kizárja a specifikáció.  És az implementáció ésszerűen egy szál szokott lenni. Nyilván lehetne elvben több szál is ha kölcsönös kizárással nyúlnak a JS VM-hez, de ez felesleges bonyolítás lenne. (Érdemes egyébként megnézni, hogy milyen várakozási sorok vannak JS-ben milyen prioritásokkal, tipikus szivatós kérdés JS esetén, hogy milyen sorrendben futnak le ezek: és ott van setTimeout(0), meg minden féle nyalánkság. Szerencsére nem vagyok JS szakértő, ezért csak szórakoztató tartalomként néztem meg ezeket, de tényleg érdekes mindenkinek jó szívvel ajánlom!)

A specifikációt megnyitottam és rákerestem a "thread" szóra: zéró találat :-)

Még jó hogy, te nagyon nagyon sötét. Idemásolom harmadszor is:
"Megmondtam, csupán csak azért, mert a JavaScript szottyod nem éri el szálként, nem azt jelenti, hogy ne lenne szál a motorháztető alatt."

Például ez kellett volna elolvasnod belőle: "inner function is returned from the outer function before being executed." Magyarán párhuzamosan futnak a hívást követően, külön szálon (NEM JavaScript szálról van szó).

Lófaszt nem, a példád konkrétan az interpretált programod processz id-jéhez tartozó, és csak az ahhoz tartozó szálakat kéri le, ezért kapsz hibás eredményt.

Nincs külön interpretált processz és interpreter processz. Egyetlen nodejs processz van, ami beolvassa a JavaScript file-t és végrehajtja. Hogy közben interpretelás és/vagy vagy compilálás történik azon a processzen belül, az részletkérdés. De továbbra is egyetlen processz van.

Nálam nem jelenik meg.

Valóban? Akkor a ps kimentet miért nem mellékelted?

Majd akkor gyere, ha a következő JavaScript kopipészthuszárkodásodat az általad írt JavaScript motoron futtatod, pancser! LOL! ROTFL! (költői kérdés, nem hiszem, hogy képes lennél valaha is egy jsmotort megírni)

const { pid, ppid } = require('node:process');

const log = (...s) => console.log(new Date(), s.join(' '));
setTimeout(() => {
  log("Lenni nem main szál",`pid: ${pid}`, `parent pid: ${ppid}`);
}, 100);
log("main szál 1", `pid: ${pid}`, `parent pid: ${ppid}`);
const t0 = Date.now();
while (Date.now() - t0 < 2000);
log("main szál 2", `pid: ${pid}`, `parent pid: ${ppid}`);

strace -tt -f -o output.txt node index.js                                             
2024-07-23T19:05:20.927Z main szál 1, pid: 27745, parent pid: 27742
2024-07-23T19:05:22.929Z main szál 2, pid: 27745, parent pid: 27742
2024-07-23T19:05:22.930Z Lenni nem main szál, pid: 27745, parent pid: 27742

A parent pid az a zsh azonosítója amiből indítottam.
output.txt

A példa szerint (https://smgui-bztsrc-55b51cf47c606e6adca67c1bd251c4bf8538ddbffd11615f1b…) a "button" kezelése akár másik szálon is történhet. Van erre is példa kód? Nem látszik semmi szinkronizációs hívás, így nem teljesen világos, hogy ez több szálon hogyan működhet.

Vagy, hogy sosem értesül a GUI thread a változáról.

Nem, ez nem fordulhat elő. Ha akár egy másik thread egyszer is meghívja az ui_refresh()-t, akkor ez is frissülni fog. De akkor is frissülhet, ha nem hív senki ui_refresh()-t, például amikor átméretezed az ablakot vagy ha ki-be csukogatsz div-eket, stb.

Vagy inkinzisztens adatot "lát".

Ez sem fordulhat elő. A view rétegben egyáltalán nincs másolat az adatodról (nincs by value átadás, csakis by address), ezáltal nincs is, ami inkonzisztens lehetne.

Erre semmi garancia nincs, hacsak nem teszel érte megfelelő szinkronizációs eszközök használatával.  Erre kérdeztem rá, hogy mivel garantálod a helyes több szálú működést. Az eddigiek alapján semmivel.

Ilyesmi problémákra gondolok:

https://stackoverflow.com/questions/944966/how-are-cache-memories-share…

https://en.m.wikipedia.org/w/index.php?title=Cache_coherence&diffonly=t…

Ilyesmi problémákra gondolok

Mit jössz itt a cache-el? A cache koherencia és a több szálú szinkronizáció ég és föld, hát még ezt sem tudod?

Értsd már meg végre, nincs semmi ilyesmi cache benne, de még csak csak by value értékátadás sincs sehol se, ezért nem lehet inkonzisztencia és mivel egy helyen írsz, sok helyen olvasol ezért versenyhelyzet sem lehetséges (az csak párhuzamos írás esetén léphetne fel, de ezt gondosan elkerültem még a tervezésnél).

De tudod mit? Amíg te itt kötözködni próbálsz, addig én vígan használom az SMGUI-t többszálas alkalmazásból és egyáltalán semmi problémám sincs vele, gyönyörűen működik, pont úgy, ahogy szeretném! Részemről a vita lezárva.

Hülye vagy, és ha így folytatod az is maradsz. 

Teljesen félreérted a hozzászólásokat. Én nem kötözködni jöttem, sőt kifejezetten udvariasan próbáltam kommunikálni (eddig).

Használd egészséggel az SMGUI-t, csak ne reklámozd, hogy thread-safe, mert az eddigiek alapján nem az. Vagy reklámozd annak, mit bánom én. Részemről is lezárva a "vita".

Hülye vagy, és ha így folytatod az is maradsz.

El vagy szállva magadtól, miközben azzal sem vagy tisztában, hogy az általad linkelt multithreading (értsd: software taskswitching és multicore scheduling) és a programokon belül használatos threading (értsd: Linux-on pthread, Windows-on CreateThread) két tök különböző dolog, és semmi, de semmi közük sincs egymáshoz. Előbbínél számít a CPU cache és a TLB, mert címtereket is kapcsol, utóbbinál pedig rohadtul nem, mert ott egy címtéren belül történik szálkapcsolás.

Én nem kötözködni jöttem, sőt kifejezetten udvariasan próbáltam kommunikálni (eddig).

Valóban? Akkor minek jössz itt cache koherenciával, miközben az SMGUI-ban nincs is cache? (És ha már itt tartunk, többszálúság esetén szó sincs megosztott memóriáról, mivel egy címtérben vannak. És mivel pthread meg WIN32 CreateThread esetén közös a címtér, tehát közös a TLB-jük is, így minden általad linkelt infó irreleváns, nem ide tartozik.)

csak ne reklámozd, hogy thread-safe, mert az eddigiek alapján nem az

És ez mi, ha nem kötözködés akar lenni? De, az SMGUI az bizony thread-safe. Cáfold meg egy PoC-al ha tudod!

Mégegyszer, most is külön szálon fut nálam a megjelenés és a kontroller, és gyönyörűen működik. Azt is teszteltem, hogy ablakonként van egy megjelenés szál, amit egyetlen közös kontroller szál kezel, ez is hiba nélkül működik (bár nem túl praktikus).

Sőt! Még az is működik, hogy külön processzben vannak, a layout által hivatkozott változók pedig egy közös mmap shared memóriaterületen! Hogy miért? Mert a változókat NEM az SMGUI definiálja, hanem te. Ha atomikusságot akarsz, akkor a TE dolgod akként deklarálni, az SMGUI-nak semmi köze a deklarációidhoz!

Próbáljátok már felfogni, miről is szól a state-mode, ez nem GTK, ami tele van fosva mindenféle túlbonyolított adatstruktúrával, ami emiatt nem is működhet többszálon megfelelő lockolás nélkül. Ez NEM ilyen, itt nincsenek ilyen adatstruktúrák, a layout NEM tartalmazza az adataid másolatát, nincs cache.

Látom csak elkezdtél utána olvasgatni.

Öcsisajt, én már 20 évvel ezelőtt is SMP-t meg multitaskingot programoztam Assemblyben. Legutóbb például ezt követtem el a témában, ami többmagos CPU-kat inicializál x86 és ARM processzorokon, és ennek is már 7 hónapja. Ebben még olyant is láthatsz, hogy direktben helyezem el a gépikódú utasítást a memóriába, mert én olyanokkal is tisztában vagyok, amit még a gcc assemblere sem tud.

De most kezdtem el csak szerinted olvasgatni a témában, mi? Úgy birom, mikor a hozzád hasonló semmirekellő zöldfülű nyikhajok próbálnak kioktatni programozásról és közben ekkora öngól rúgnak! (szarkazmus)

attól tartok értelmes beszélgetést továbbra sem lehet veled folytatni

Lefordítom: beijedtél, mert csak a szád nagy. Egy működő PoC-ra lenne szükséged ahhoz, hogy velem érdemben diskurálhass.

Úgy túnik, a topikot megtalálták a semmihez sem értő, de iszonyat nagy pofájú trollok. Nagyon szépen köszönöm nekik, hogy az SMGUI topikomat folyamatosan a főoldalon tartják! :-D

Gratulálok! Magam nem fejlesztek C-ben, de szerintem akkor is elismerésre méltó minden szoftver, ami közkincs.

Furcsa érzés nézni a random kötekedő hozzászólásokat, nem értem embereknek mi baja a szabad alkotással.

  1. Volt egy probléma.
  2. Valaki megoldotta a problémát, ahogy NEKI jó.
  3. Opcionális: mellé írja, hogy kis projekt, és amúgy is csak AT-harddisk winyója van amit támogatni tud
  4. Másik hősünk idejön, hogy nem így oldaná meg meg ez nem is oldja meg.

Bro... ingyen van. Ha tetszik, használd. Ha nem tetszik, ne használd. Ha tetszene, de nem pont így, akkor jó hír: megoldhatod úgy, ahogy szerinted szupi.

Everyone is a winner*

Köszönöm!

Á, hagyd csak, az van, hogy semmi hozzáértésük sincs, programozni nem tudnak, csak JS kódokat kopipasztáznak, így posztok irogatásában élik ki az emiatt érzett frusztrációjukat. Én csak azért etetem őket, mert főoldalon tartják a topikom...

Igazából azok után, hogy megírtam, "Ha neked más igényed van, mint nekem, akkor használj másik libet és kész", értelmetlen minden megszólalásuk. De hát a magyar nyelvű szövegértés sosem tartozott az erősségeik közé...

Azért a tényszerűség kedvéért: én elismertem, hogy sok hasznos dolgot csináltál. Ez a cucc is hasznos. Viszont ha konkrétan hamis/hibás állításokat teszel valami kapcsán, akár erintőlegesen is, akkor hadd válaszoljak már rá. A cáfolatokat az állításaimra topik megfelelő szálaiban várom.

Na tessék, emlegetett majom troll. Még ide is idepofázik, mikor a cáfolatokat az állításaira a megfelelő szálban már bőven megkapta, mégis feltűnési viszketegségében képtelen megállni, hogy ne böfögjön még ide is.

Viszont ha konkrétan hamis/hibás állításokat teszel valami kapcsán

Itt most magadról beszéltél ugye? Merthogy eddig minden állításodat konkrét kódrészletekkel meg MSDN idézetekkel cáfoltam. MINDET.

Valóban nem, mert még most sem tudtál felmutatni az égvilágon semmit sem. No meg nem mintha dűlőre kéne jutnom bármiben is veled, nem egy pályán focizunk.

Komolyan kezdelek őszintén megsajnálni. Az ugye megvan, hogy eszem ágában sincs komolyan venni egy refrencia nélküli szájhőst (ahogy senki más sem fog), csak azért húztam az agyad és kértem tőled referenciát, hogy posztolgass és frissen tartsd a topikot? Pedig konkrétan, kerek-perec le is írtam ezt, nem tudom, mit mondjak, hogy még ezek után sem esett le... Tisztában vagyok vele, hogy nincs semmi referenciád, se szakmai tapasztalatod, se hozzáértésed, csak kihasználtam a hülyeséged.

Ismétlem: ne az egyéb munkáimmal foglalkozz, hanem az állításaimmal. Ha mondjuk kőműves vagy fényképész lennék, nem lehetne igazam a szálkezelés kapcsán? Sajnálom, hogy ez tűnik az utolsó mentsváradnak, hogy addig nem veszel figyelembe, amíg nem mutatok ezt meg azt. Ha elmondanám, hogy mit csinálok, mi lenne a következő? Hogy addig nem válaszolsz, amíg nem küldök képet arról, hogy mekkora autóm van? És ha nekem van nagyobb autóm? Ez szerintem nem vezet sehová.

Én amúgy nem bánom, ha pörög a topikod. Már korábban is írtam, elismerem, hogy hasznos amit csinálsz. És közben szórakoztat az eszmecsere, amiben hol kevesebb, hol több a szakmaiság.

Egy kis frissítés.

- Lett egy új mezőtípus, az UI_STATUS. Ez ugyanaz, mint az UI_LABEL, csak figyelembe veszi, hogy melyik mező fölött áll éppen az egér, és annak a cimkéjét írja ki.
- Az UI_IMAGE lehet kattintható is (ugyanúgy működik, mint az UI_BUTTON, csak nincs kerete)
- Átírtam a GLFW-s backendet shaderesre.
- Végre megtaláltam, hogy kell kikapcsolni a gitlab-on, hogy ne irányítson át egy elcseszett URL-re :-) Valamiért nemrég ez lett a default. Ha másnak is kéne: Deploy - Pages - Use unique domain mellől kell kivenni a pipát.

Ami a backendet illeti, kiderült, hogy VirtualBox alatt a wines GuestAdditions által feltelepített videómeghajtó bugos, és nem működik az old-school OpenGL API-val, akkor sem, ha nem konfiguráltál shadert és direkt beállítottad a kompatíbilitási szintet. Emiatt átírtam shaderesre, ami alapból OpenGL 3.3 core profile-ú, de gondolva az Androidos portra, az UI_GLFW_GLES2 define-al átkakcsolható VBO mentes, legfaékebb shaderre. Az UI_GLFW_NOSHADER define pedig visszaállítja a korábbi shader mentes működést (aminek nagy előnye, hogy nem kell hozzá bővítménybetöltő, és a VirtualBox-ot leszámítva mindenhol csont nélkül működik).

Apropó, bővítménybetöltő: GLAD és GLEW is támogatott lett (nincs konfiguráció, amelyiket beincludeoltad, azt használja és kész). Linux alatt erre nincs szükség, de sajnos Windows-on a gyári opengl32.dll olyan ősrégi, hogy még textúrákat sem tud kezelni GL bővítmények betöltése nélkül.

Az SDL és natív X11 backendeknél nincs ilyen szívás, azok Just Works (TM). Az SDL alapból fallbackel egy szoftveres renderer-re, ha a bővítménybetöltés nem sikerülne, az X11-nek meg nem is kell ilyesmi, mert csak XImage-ket blittel, az Xserver meg tudja, mit és hogy kezdjen vele.

Derekasan tolod. Ez már így leírva is iszonyat fejlesztési munkának tűnik, én évek alatt se tudnék ilyen összetett projektet lefejleszteni, nem hogy néhány hét leforgása alatt.

Egyébként, most hogy már megírtad, meg egyre több backendet, funkciót támogatsz, most fogod látni, hogy a GUI műfaja milyen ménkű összetett, komplex, sok réteges. Én ezért is nyergeltem át CLI/TUI megoldásokra, mivel egyszerűbbek, megbízhatóbbak, kisebb a függőségük, és ha jól vannak használva (alias-ok, gyorsbillentyűk, stb.), még hatékonyabbak is.

The world runs on Excel spreadsheets. (Dylan Beattie)

Derekasan tolod.

Kösz!

Ez már így leírva is iszonyat fejlesztési munkának tűnik, én évek alatt se tudnék ilyen összetett projektet lefejleszteni, nem hogy néhány hét leforgása alatt.

És akkor vedd hozzá, ez nekem csak egy apró kis mellékprojekt, igazából csak azért kell, hogy a fő projektemmel haladhassak...

most fogod látni, hogy a GUI műfaja milyen ménkű összetett, komplex, sok réteges

Eddig is tudtam, nem az első rodeóm :-)

Ráadásul pont azért vágtam bele, mert rengeteg GUI toolkit-et használtam már, de egyikkel sem voltam megelégedve. A QT egy iszonyat, parás a licensze, és csak C++. A wxWidgets egy fokkal jobb, licenszpara sincs vele, de az is csak C++. A GTK konkrétan egy rakás fos, ahol a fejlesztők csak megjátszották, hogy értik az MVC-t, de valójában lövésük sem volt róla, ezért rettenetesen elkefélték már a tervezésnél. A GDI-nek megvannak a maga kis hülyeségei, de az valójában piszok jól van megtervezve, az egyetlen bajom vele, hogy nem portolható, Win only. Ja és ezek közül egyik sem fordul emscipten-el, stb. stb. stb.

Pont ezért örültem meg annyira a Nuklear-nak, mert látszatra pontosan azt nyújtja, ami nekem kell: C-ből is használható, portolható, Linux-on, Windows-on és emscripten-el is fordul, nincs függősége. Na de aztán amikor elkeztem volna használni, jött a feketeleves, igazából egy rakás fos az is. Az, hogy iszonyat mennyiségű glue kódot kell írni, szopás, de még hagyján. Viszont az, hogy a view és controller rétegeket nem lehet vele külön szálra rakni, na amiatt egy bazi nagy no-go. Így kényszerből vágtam neki ennek a mellékprojektnek.

Én ezért is nyergeltem át CLI/TUI megoldásokra

Ez nálam nem opció, mivel grafikát kell megjeleníteni. Egyébként egyetértünk, hogy a CLI sokkal hatékonyabban használható. A TUI-ban már nem vagyok olyan biztos, egy jól megírt TUI pontosan ugyanolyan összetettségű, mint egy GUI, és ha jól van kivitelezve, akkor felhasználói szemszögből a használatában sincs semmi különbség köztük (mindkettő irányítható egérrel, gombokkal és gyorsbillentyűkkel egyaránt). Itt most nem olyan TUI-ra gondolok, mint a Linux kernel dialog-ja, hanem az olyanokra, mint anno a Borland TurboC IDE-je volt, meg a Norton cuccai.

Nahát, most látom, előbbit mondernizálták, portolták Linuxra és kiadták GPL alatt. Jó, a jessie nem mai darab, de mindenképp kortársabb, mint a DOS-os verzió volt :-)

Kérdés: gondolkodom azon, hogy portolom Linux framebuffer backendre. Lenne rá igény? Azért kérdezem, mert elég nagy meló (jöval több, mint a többi backend, lévén a keyboard layout-okat is magadnak kell lekezelned). A másik, amin gondolkodom, az a natív Win GDI (mind a GLFW, mind az SDL fordul most is Win-re, itt a kérdés az, van-e igény ezek nélküli Windows támogatásra). Ez utóbbit egyszerű megcsinálni, csak nem tudom, mennyire van értelme.

(Rust-rajongó vagyok)

Tetszik a munkád, elismerésem!

Azzal nincs még gond, ha valaki Rust rajongó, meg azt tanulta, abban tudja a dolgait a legjobban írni. Nyilván a saját projektednél te mondod meg, hogy miben írod, neked hogy könnyebb.

A gond a térítőkkel van, akik mindent el akarnak avultatni, ami nem abban van írva, meg előírják mindenki másnak is, hogy mindent csak Rust-ban lehet írni, különben nem menő.

The world runs on Excel spreadsheets. (Dylan Beattie)

Szerkesztve: 2024. 07. 19., p – 06:15

Na még pár újdonság:

- ui_table.h modul, ami táblázat és grid konténertípust is ad egyszerre
- a táblázat képes adatmásolás nélkül struct tömböket megjeleníteni, minden oszlop külön beállítható (típusa, mérete, akár százalékban is, mint HTML-nél), és rendezhető is (libc-s qsort-ot használ)
- grid esetén meg kell adni az oszlop méretét pixelben és minden cella ugyanolyan típusú, egyébként pont ugyanaz, mint egy táblázat
- lett ikongomb, ami ugyanúgy működik, mint egy checkbox, de csak akkor jeleníti meg a képet, ha be van pipálva
- sok apró javítás (pl file pickernél ha a szkrollbárra kattintottál, nem volt vizuális visszajelzés, nem nyomódott be, ilyenek)

A táblázatnál meg kell adni egy ugyanolyan űrlaplistát, mint egyébként, csak mutató helyett a struct mezők offsetof értékét tárolja. Ez szolgál a fejléchez és az egyes oszlopok típusát is megadja. Ez azért jó, mert rühelltem a GTK-ban, hogy nem tudom megjeleníteni az adataimat, hanem folyton másolgatni kell a struct tömbömből a GTKTreeView-ba, és ha módosítás történt, akkor meg vissza. Na itt nincs ilyen, a state-mode GUI filozófiához híven csak hivatkozol a már meglévő változókra, a módosításhoz meg mindössze label mező helyett valamelyik input mező típust kell megadni, és kész is.

Az ikongomb majdnem ugyanaz, mint a kép, mindkettő ui_image_t képet rak ki, mindkettő kattintható. A különbség az, hogy míg a kép esetén mindig látszik, és kattintásnál behelyezi az értéket (mint a radiobutton), addig az ikongomb csak akkor rakja ki a képet, ha be van pipálva, és XOR-olja az értéket (mint a checkbox). Ha egyszerűen akarnám elmagyarázni, mire jó ez, akkor azt mondanám, gondoljatok a GIMP rétegeinél a szem vagy lánc ikonra, na ez pont ugyanazt csinálja.

Több, mint 3000 megtekintés. Asszem innentől nincs a továbbiakban szükség arra, hogy a trollok a főoldanon tartsák a topikot. Der Mohr hat seine Schuldigkeit getan, der Mohr kann gehen!
A továbbiakban csakis update bejelentésekkel és csak technikai kérdésekkel foglalkozom ebben a topikban.

A troll aki nem ert veled egyet, es nem dicser?

Egyebkent, hogy ontopic legyek, nem akarsz ebbol a cuccbol egy dialog/zenity szteroidos valtozatat csinalni (mindegyiknek van jopar hulyesege)? A francnak van kedve mindenfele nyelveken programot irni, amikor bashbol minden is megoldhato. :)

A troll aki nem ert veled egyet, es nem dicser?

Nem. A troll az, aki idejön és ok nélkül elkezd offtopic baromságokat összehordani, és még akkor sem áll le, amikor konkrét SpiderMonkey meg V8 kódrészlettel cáfoltam az állításait. Mert hát troll, mit neki tények meg valóság, ugye.

Egyebkent, hogy ontopic legyek, nem akarsz ebbol a cuccbol egy dialog/zenity szteroidos valtozatat csinalni

Nem terveztem. A célom vele az, hogy pár projektemben felhasználjam, mert ott kifejezetten szükség van egy multiplatform UI kitre, ami minden rendszeren pixelpontosan ugyanúgy néz ki.
De pont azért adtam ki MIT licensz alatt független repóként is, hogyha valaki szeretné, akkor csinálhat belőle dialog/zenity alkalmazást, ennek semmi akadálya.

Nem. A troll az, aki idejön és ok nélkül elkezd offtopic baromságokat összehordani, 

Már ne haragudj, de az első hozzászólásom a topikban arról szólt, hogy a multithread UI framework-ök sokak álláspontja szerint problémákkal küzdenek, és hogy nem véletlen, hogy a legtöbb UI framework végül egyszálú lett. Én reméltem, hogy ebből kijöhet egy értelmes párbeszéd is.

 akkor sem áll le, amikor konkrét SpiderMonkey meg V8 kódrészlettel 

Azért nézd meg azokat a kódrészleteket újra, mert nem igazolják a gondolatodat. A lefuttatott tesztprogram sem igazolja a gondolatodat. De mint mondtam, erről úgysem fogjuk meggyőzni egymást. De amúgy örülök, hogy az aszinkron IO és GDI vélhetően kevesebbek által ismert témája helyett a sokkal többek által ismert JavaScript event loopra sikerült terelned a szót, így egy szélesebben értő közönség előtt csinálsz totál hülyét magadból.

Igen, ez először az aszinkron IO kapcsán jött, amikor kért egy példát olyan modellre, ahol egy szál van, és sok pending IO. Erre egy példa a JavaScript. (És igen, itt is elismétlem, mielőtt megint jön vele valaki, hogy belül a JavaScript motorban van több szál, de nem azért, hogy minden egyes IO egy külön szálon fusson, tehát nem az aszinkron IO miatt)

Hogy bekergetett-e az erdőbe? :D Neked is javaslom, hogy ne nekem higgy, hanem a mellékelt tesztprogramoknak. Azok mondják meg az igazságot.

Valójában egyik sem. Az SMGUI nagyon körültekintően úgy lett megtervezve és implementálva, hogy mindegy legyen neki, hogy egy szálas vagy többszálas programból használod-e.

Magyarán nincs benne olyan kódrészlet, ami gondot okozhatna a többszálúság esetén, azt meg, hogy esetleg a backend többszálú-e (mint a GLFW pl), úgy küszöbölöm ki, hogy ciklikus buffert használok az eventekre, aminél a backend a kizárólagos producer, az ui_event() hívás meg a kizárólagos consumer, így itt sincs szükség szemaforokra, mutexekre, futexekre meg lockolásra. De asszem ez már túl bonyi a legtöbb itteni kopipészt huszárnak, akik azt sem tudják, mi az a ciklikus buffer, nemhogy azt tudnák, miként lehet lockolásmentes queue-ként alkalmazni.

Sajnos az ilyen jellegű gondos tervezés meghaladja a legtöbb itteni forumozó felfogási képességeit, mert csak a stackoverflow-os kódmintákat ismerik, sosem hallotak még ilyesmiről.

A JavaScript programozási modellje egyszálú. A JavaScript motor használhat segédszálakat egyéb célokra, pl. JIT, GC stb. De az a rész, amikor a konkrét JavaScript kódod hajtódik végre, az egy szálon történik. És ahonnan indultunk fentebb: amikor IO-t indítasz, nem allokál egy új háttérszálat az egyes IO műveletekhez.

A Node.js és a V8 motor szálkezelése összetett folyamat, amely az asszinkron I/O hatékony kezelését célozza meg. Az alábbiakban bemutatom, hogyan néz ki ez a folyamat a szálkezelés szempontjából:

1. **Fő szál (Main Thread)**: A Node.js alkalmazások egyetlen szálon futnak, amelyet fő szálnak nevezünk. Ez a szál futtatja a JavaScript kódot a V8 motorban és kezeli az eseményhurkot.

2. **Eseményhurok (Event Loop)**: Az eseményhurok szintén a fő szálon fut. Az eseményhurok figyeli az eseményeket, és végrehajtja a regisztrált callback-eket, amikor a megfelelő események bekövetkeznek. Az eseményhurok felépítése több fázisra tagolódik, amelyek mindegyike különböző típusú műveleteket kezel (pl. I/O, timer, stb.).

3. **libuv és I/O műveletek**: A Node.js a libuv könyvtárat használja a nem blokkoló I/O műveletek kezelésére. A libuv egy többszálú könyvtár, amely külön szálakat használ a különböző I/O műveletek végrehajtására. Amikor egy I/O műveletet indítunk (pl. fájl olvasás), a libuv egy vagy több háttérszálat használ az I/O művelet végrehajtásához, így a fő szál szabadon marad más feladatok kezelésére.

4. **Worker Threads**: A Node.js-ben a `worker_threads` modul lehetővé teszi a több szál használatát a CPU-intenzív feladatok végrehajtására. Ezek a szálak külön V8 példányokkal rendelkeznek, és saját eseményhurokkal futnak. A fő szál és a worker szálak közötti kommunikáció üzenetküldésen keresztül történik.

5. **Thread Pool**: A libuv egy belső szálmedencét (thread pool) használ az I/O műveletek kezelésére. Ez a szálmedence általában 4 szálat tartalmaz, de a `UV_THREADPOOL_SIZE` környezeti változóval növelhető. A szálmedence feladata, hogy kezelje azokat az I/O műveleteket, amelyek nem képesek azonnal befejeződni, mint például a fájlműveletek és a DNS lekérdezések.

6. **Fő szál és szálmedence interakciója**: Amikor egy I/O műveletet elindítunk, a fő szál regisztrálja a műveletet az eseményhurokban, majd a libuv átadja a feladatot egy szálnak a szálmedencében. Amikor a művelet befejeződik, a libuv visszaadja az eredményt a fő szálnak, amely végrehajtja a regisztrált callback-et az eseményhurok következő iterációjában.

Ezzel a megközelítéssel a Node.js képes hatékonyan kezelni a nagyszámú párhuzamos I/O műveletet anélkül, hogy blokkolná a fő szálat, miközben lehetőséget biztosít a párhuzamos számítási feladatok végrehajtására a worker szálakon keresztül.

By ChatGPT

Egyetértek. Amúgy a topik másik részében is sikerült egészen szakmai irányba kanyarodni, és ott bzt legutóbbi néhány hozzászólásában sem volt már lealacsonyító sértegetés. És ismétlem, én elismerem, amit bzt csinál, de attól még szerintem lehet helye észrevételeknek.

A lényeg benne van, hogy az aszinkron IO-ban nem tartozik minden egyes IO-hoz egy háttérszál, és én végig erről írtam.

Még véletlenül sem ezt írtad eddig soha, hanem konkrétan azt, hogy:
- Súlyos tévedés, hogy az aszinkron azt jelenti, hogy többszálú (innen indult az egész)
- az IO műveletekhez nem kell több szál
- Aszinkron IO-nál nincs másik szál.
- És nem lesz 10 háttérszál sehol, OS szinten sem, ami arra vár, hogy a connect rendszerhívás befejeződjön. Pedig 10 folyamatban lévő connect-ed van.
- JavaScript engine-ek használnak több szálat, a megfelelő helyen a megfelelő célra. De nem az aszinkron IO-ra.
- Amikor valamilyen esemény bekövetkezik, pl. egy IO sikerre vagy hibára fut, akkor az adott callback hívódik meg azon az egyetlen szálon.
- az aszinkron IO megtörténik a háttérben, szál nélkül.
...stb.
Mindvégig egyértelműen azon görcsöltél, hogy többszálúság nélkül létezhet aszinkron.

Igen, ez először az aszinkron IO kapcsán jött, amikor kért egy példát olyan modellre, ahol egy szál van, és sok pending IO.

Francokat, NEM is ezt kértem. Azt kértem, drága értelmi fogyatékos troll fórumtárs, hogy egyetlen szálú aszinkronra mutass példát, és ezzel még mindig, most is adós vagy (és leszel is, mert még az AI szerint sem létezik ilyen JS motor). Az egyetlen szál több pending IO-ra pedig ÉN mondtam NEKED példát, méghozzá itt, szóval ha valóban ez lett volna a kérdésem, akkor is beégtél!

bzt legutóbbi néhány hozzászólásában sem volt már lealacsonyító sértegetés

Igazából de, valójában olyan szinten oltottalak a legutóbbi pár posztomban, mint még soha előtte. Meg sem lep, hogy még csak le sem esett.

De szerintem ezt itt zárjuk le. Ez a téma bzt SMGUI toolkit-jéről szól és nem arról, hogy a Js motor hány szálon és hogyan futtatja az asszinkron I/O-t

ÁMEN! (Gyengébbek kedvéért, jelentése "úgy legyen!")

Oké, a nodejs motorja használ fix számú segédszálat az IO-hoz, én belátom, hogy ebben volt tévedésem. Remélem te is hasonlóan belátod tévedéseidet, leginkább pl. annak kapcsán, hogy a JavaScript callback-ek szerinted külön szálon futnak. Amire mellesleg az AI is azt mondta, hogy nem így van, hanem mindegyik callback az egyetlen fő szálon fut le.

De visszatérve az aszinkron IO-ra, azt továbbra is tartom, hogy az aszinkron IO nem jelenti azt, hogy több szál kell hozzá.

 egyetlen szálú aszinkronra mutass példát

Erre egyébként alább küldtek is konkrét kódrészletet.

És továbbra is a leginkább lényeges az, hogy nem szükséges annyi szál, ahány IO folyamatban van. Ez látszik is abból, hogy a nodejs használ fixen 4 segédszálat, mégis lehet 30 connect egyszerre folyamatban. Ezt világosan kimutatta a korábban küldött program, a mérés szerint közben egyetlen új szál sem indult, és mégis megoldotta a 30 párhuzamos connect-et. És lásd be, hogy ennek kapcsán továbbra is elég komoly tévedésben vagy pl. itt: "egy másik szálon új kapcsolat indul mielőtt még az előző végezne, mert független szálakon futnak"

Oké, a nodejs motorja használ fix számú segédszálat az IO-hoz, én belátom, hogy ebben volt tévedésem.

Remek. Mi a retkes fasznak kötözködsz akkor még mindig?

Remélem te is hasonlóan belátod tévedéseidet, leginkább pl. annak kapcsán, hogy a JavaScript callback-ek szerinted külön szálon futnak.

Nem volt tévedésem, konkrétan ezt állítottam: "Akkor is, ha a többszálúság csak a motorháztető alatt található és nincs direktben kivezetve a JavaScript API-jára, még akkor is". Nem cáfolta ezt az AI válasza sem, sőt, kifejezetten megerősítette, hogy így van.

Erre egyébként alább küldtek is konkrét kódrészletet.

HIBÁS kódrészletet. Az még csak nem is aszinkron, hanem konkrétan multiplexelt (és ezt a példát ÉN már hoztam, és azt is megállapítottuk, hogy egyetlen JS motor sem multiplexel)

És továbbra is a leginkább lényeges az, hogy nem szükséges annyi szál, ahány IO folyamatban van.

Na de te nem is ezt állítottad, hanem hogy "Aszinkron IO-nál nincs másik szál." Egyetlen egy plusz szál se a fő szálon kívül.

Akárhogyis csűröd, csavarod, egyértelmű, hogy hülyeségeket hordál össze, és még azután is tolod a faszságodat, hogy BEISMERTED, TÉVEDTÉL.
Na pont emiatt vagy egy troll, az internetes kommuna legalja, a leszánalmasabb kis senki, egy totál nímand, akin mindenki csak röhög.

Attól még, hogy volt egy része a dolognak, ahol pontatlan voltam, nem jelenti azt, hogy mindenben tévedés lenne, amit írtam.

 

 // ez itt lenni NODEJS SZÁL #1
    client.connect(1337, hostIp, () => {
      // ez itt lenni NODEJS SZÁL #2, futni egyszerre SZÁL #1 mellett párhuzamosan
      console.log(`Client ${i} connected`);
      // SZÁL #2 itt most terminálni, SZÁL #1-től függetlenül, az futni tovább
    });
    // ez itt lenni továbbra is NODEJS SZÁL #1, futni SZÁL #2-től függetlenül

Nem volt tévedésem, konkrétan ezt állítottam: "Akkor is, ha a többszálúság csak a motorháztető alatt található és nincs direktben kivezetve a JavaScript API-jára, még akkor is". Nem cáfolta ezt az AI válasza sem, sőt, kifejezetten megerősítette, hogy így van.

Idézet az AI-tól, ha már bízunk benne: "Az eseményhurok szintén a fő szálon fut. Az eseményhurok figyeli az eseményeket, és végrehajtja a regisztrált callback-eket." Ezt azért vesd össze azzal a kódrészlettel, amit most idéztem tőled.

Mit görcsölsz, amikor már beismerted a tévedésed?

Ezt azért vesd össze azzal a kódrészlettel, amit most idéztem tőled.

Összevetettem, semmi köze hozzá. Az, hogy figyeli az események státuszát, és hogy azok az események milyen implementáló után következnek be, ég és föld. Persze minek is magyarázom, úgysem érted.

És azt is megmondtam már, hogyha maga az IO pollozása lenne a esemény, akkor nem is beszélhetnénk aszinkronról, mert az MULTIPLEXELÉS lenne. De nem így van, idézet az AI-tól, ha már bízunk benne (kiemelés tőlem): A Node.js és a V8 motor szálkezelése összetett folyamat, amely az asszinkron I/O hatékony kezelését célozza meg." Tehát még véletlenül sem egyetlen szálon történik az aszinkron IO, állításodal ellentétben.

És különben is, már beismerted, hogy tévedtél, akkor mit akarsz még itt, troll?

Pont a hálózati hívásokat tudjuk epoll API segítségével nonblocking módon kezelni szálak nélkül Linuxon. A connect hívásra jövő választ is epoll eseményként kapjuk meg az egyetlen feldolgozó szálunkon.

AFAIK a fájlok olvasására sajnos nem működik az epoll, meg még van néhány channel típus, amire szintén nem működik és azokhoz szálakat kell indítani. (Például a /dev/input/eventX-re próbáltam és csodálkoztam, hogy nem működik pedig logikus volna, hogy működnie kellene.) De ez implementációs részlet, ha a Linux normálisan _minden_ file deszkriptorhoz megvalósítaná az epoll API-t, akkor egyetlen szálon működhetne az egész JS interpreter úgy, hogy mindig run to completition-ig futtatja az aktuális végrehajtandó taszkot és utána a queue-kból kiveszi a következőt, amikor meg elfogy minden végrehajtható taszk, akkor a külső eseményekre vár (időzítők, fájlműveletek, hálózat, stb) egyetlen epoll kontextuson keresztül.

Hogy mennyire lehet több IO csatornát egyetlen szálon kezelni, arra álljon itt egy mikrovezérlős példa: két UART van rajta, és ami az egyiken bejön, azt a másikra írjuk. Mindezt JS-szerű, JS szemantikájú pszeudókóddal és C szemantikájú pszeudókóddal demonstrálom, hogy hogyan működik:

uart1.initialize();
uart2.initialize();

uart1.onreceivebyte(function(b){uart2.write(b);});
uart2.onreceivebyte(function(b){uart1.write(b);});

És a C ami ezt megvalósítja a JS szemantika szerint helyesen - szálak nélkül:

// UART interfészek körkörös DMA-ra konfigurálása: mind az input, mind az output IRQ nélkül magától DMA-zik körkörösen ringbuffer-szerűen
uart_initialize(UART1);
uart_initialize(UART2);

while(true)
{
    while(uart_hasdata(UART1))
    {
       byte b=uart_read(UART1);
       uart_write(UART2, b);
    }
    while(uart_hasdata(UART2))
    {
       byte b=uart_read(UART2);
       uart_write(UART1, b);
    }
    
    // Ha megvalósítottunk eseménykezelést, akkor sleep-be tehetjük a processzort, ha nem, akkor ezt kihagyjuk és busy loopolunk:
    waitForDataAvailable(UART1, UART2);
}

Mindezt JS-szerű, JS szemantikájú pszeudókóddal

Ez a példa semmit nem mond, ékes bizonyítéka annak, mekkora sötétség dübörög a fejetekben. Kopipészt huszárok vagytok, csak a magas szintű API hívásokról van némi homályos sejtésetek, de amint az a kérdés, hogy mi is történik a motorháztető alatt alacsony szinten, beadjátok a kulcsot, fingotok sincs semmiről!

Az "initialize" implementációját mutasd inkább, ha labdába akarsz rúgni!

Idióta, dilettáns banda, menjetek el kertésznek vagy építőmunkásnak, mert a PROGRAMOZÁS NEM NEKTEK VALÓ.

Hogy mennyire lehet több IO csatornát egyetlen szálon kezelni, arra álljon itt egy mikrovezérlős példa

Te ostoba, a példád még véletlenül sem aszinkron IO-t használ, hanem kifejezetten a multiplexelt IO iskolapéldája. Tudod te egyáltalán, mi történik a "waitForDataAvailable(UART1, UART2);" hívás közben? Fogadjuk, fingod sincs róla! Elárulom, pontosan az, mint a select() rendszerhívás közben POSIX-on (és amit egyetlen egy JS motor sem használ, de már ezt is tisztáztuk korábban, csak hát magyarul szövegérteni nem menni, így nem tudni, hogy JS motor nem multiplexelni, ugye?)

Esetleg kozmodomorra nem kívánsz példát hozni? Na az pont ugyanennyire lenne releváns aszinkron IO példaként, mint ezek.

Pontosan azért hoztam mikrovezérlős példát, mert ebben nincsen fekete doboz, aminek a működését nem ismerjük, illetve nem tudjuk befolyásolni. A példában két streamet kezelünk párhuzamosan aszinkron IO API-t használva úgy, hogy egyetlen szálat futtatunk a CPU-n. A JS-szerű pszeudókódban van a closure. A C-szerű pszeudókód pedig mutatja, hogy ezt hogyan hajtanánk végre egyetlen szálon. Persze az objektumok dinamikusan lennének létrehozva, ha ez egy valódi JS interpreter lenne, de a végrehajtás ütemezése pontosan ugyanez lenne.

Direkt írtam, hogy a waitForDataAvailable használata opcionális emiatt még azzal sem lehet kötözködni, hogy az interrupt az egy külön szál. Mert nem kell interrupt sem. Egyetlen szál van, ami sorban feldolgoz mindent. Ez a JS szemantikája is, nincsen több szál a specifikációban, és ha úgy akarjuk, akkor az implementációban sem. És még a kernelt is meg lehetne úgy csinálni, hogy ugyanazon a szálon fusson amin az alkalmazás is fut - ahogy mikrovezérlőn meg lehet csinálni, ugyanúgy PC-n is meg lehetne, csak 0-ról újra kellene írni mindent hozzá. Neked nem lenne gond, mert mindenhez értesz. Én nem szándékozok OS-t írni a közeljövőben.

Ha belegondolsz mivel a JS specifikációja az, hogy _sorban_ hajtja végre az eseménykezelőket, ezért a bufferelésen kívül nincsen szükség párhuzamos működésre egy JS interpreterben. A bufferelést pedig a modern mikrovezérlők automatikusan megcsinálják (körkörös DMA) anélkül, hogy a programnak aktívan csinálnia kellene bármit. Ezért lehet a JS szemantikát megvalósítani mikrovezérlőn egyetlen szálon IRQ nélkül.

>kozmodomor

Érdekesen hangzik, de nem találtam hozzá specifikációt a neten.

A példában két streamet kezelünk párhuzamosan aszinkron IO API-t használva

Hát nem. Látom még azt sem tudod, mi az a multiplexelés.

A C-szerű pszeudókód pedig mutatja, hogy ezt hogyan hajtanánk végre egyetlen szálon.

Mit mutat?

ebben nincsen fekete doboz, aminek a működését nem ismerjük

JAJJ NE, már fáj a hasfalam a röhögéstől! Ennyire hülye tényleg nem lehetsz! Nyugtass meg, hogy csak Rogán propagandista troll vagy, és nem programozóként dolgozol!

Ha nincs fekete doboz, na akkor a "waitForDataAvailable(UART1, UART2);" vajon mi???? És mégis hol van az implementációja, te nagyon degenerált? Na és az "uart1.initialize()" implementációja hol van?

Komolyan üzenem a főnöködnek, hogyha programozóként dolgozol, akkor sürgősen rúgjon ki, mert SOKKAL jobb lesz a cégnek nélküled. Ez nem sértés, hanem halál komolyan mondom.

Nos, gondoltam hagyom ezt a topikot, mert volt egy pont, ahol az AI válasza alapján úgy tűnt, hogy tévedésben vagyok, meg bzt-vel úgysem lehet értelmes stílusban kommunikálni.

De azért gondoltam csak validáljuk már le ezt. És a következőt találtam, nem máshol mint a libuv honlapján https://docs.libuv.org/en/v1.x/design.html

"The event loop follows the rather usual single threaded asynchronous I/O approach: all (network) I/O is performed on non-blocking sockets which are polled using the best mechanism available on the given platform: epoll on Linux"...

Úgyhogy most kétségeim támadtak, hogy vajon a libuv fejlesztőknek (és magamnak) higgyek, vagy pedig bzt-nek, aki pedig már majdnem meggyőzött aról, hogy csak akkor beszélhetünk aszinkron IO-ról, ha több szálunk van.

Úgyhogy most kétségeim támadtak

Ne legyenek, olvass inkább utánna. Ez, amit itt leírnak, egyértelműen multiplexelés, azt pedig BÁRMELYIK szakirodalom megmondja neked, hogy az NEM aszinkron, hanem szinkron művelet (mivel aktív pollozás történik, és egyszerre csak egy nem-blokkolt fd-vel képes foglalkozni).

De tényleg bazdmeg, vegyél már elő egy SZAKKÖNYVet, és olvasd el, mert az alapfogalmakról nincs semmi lövésed.
Mittomén, Tanenbaum könyv I/O fejezet vagy akármi.

Vagy bármelyik hálózatos könyvet, tényleg mindben le van írva, például (kiemelés tőlem): Using these definitions, the first four I/O models (blocking, nonblocking, I/O multiplexing, and signal-driven I/O) are all synchronous because the actual I/O operation (recvfrom) blocks the process.

a libuv fejlesztői is mind tehetségtelen trollok meg kopipészt huszárok

Olvass, bammeg! Arról van itt szó, hogy TANENBAUM mellett az ÖSSZES SZAKIRODALOM mást állít, mint ezek, úgyhogy nyilván ők tévednek (nem is kicsit). Ne hogy már a teljes szakirodalom tévedjen, seggarc!
De nem menni magyar nyelvű olvasás meg szövegérteni még mindig mert lenni fillipínó cseredijják vagy mi?

Menjél el inkább kertésznek vagy építőmunkásnak, mert a PROGRAMOZÁS NEM NEKED VALÓ.

Azért remélem érzed a kognitív disszonanciát. Egész eddig próbáltál idézni SpiderMonkey-ból, V8-ból (aminek kvázi a libuv a része) kódrészleteket. Most hogy kiderült, hogy igazából a libuv-nál határozottan állítják, hogy márpedig létezik egyszálú aszinkron IO, akkor már egyből ők is "tévednek (nem is kicsit)".

Azért remélem érzed a kognitív disszonanciát.

Nem, mert nincs semmiféle disszonancia. A szakirodalom is PONTOSAN azt mondja, amit én, tökéletes az egyetértés, csak Te nem vagy képes felfogni.

Most hogy kiderült, hogy igazából a libuv-nál határozottan állítják, hogy márpedig létezik egyszálú aszinkron IO

Mi derült ki? Csak annyi, hogy valami random honlapon a saját cuccáról hazudozik valami arc?
Már bocs, de ha komolyan azt állítod, hogy Tanenbaum könyvei és az összes szakirodalom és egyetelmi tananyag hibás, csak mert valami jöttment honlapon olvastál valamit, na akkor te tényleg irdatlanul ostoba vagy.

Ja, ha random honlapokon múlik, akkor tessék, itt van pár, mind szerint SZINKRON A MULTIPLEXELÉS (különös tekintettel ajánlom figyelmedbe az első linket, Tanenbaum Hálózatok könyvét):
https://github.com/gsahinpi/acm361/blob/master/Computer%20Networks%20-%…
https://betterprogramming.pub/internals-workings-of-redis-718f5871be84
https://www.thedailyprogrammer.com/2016/09/network-programming-io-multi…
https://www.ibm.com/docs/en/i/7.3?topic=concepts-io-multiplexingselect
https://www.rubberducking.com/2018/05/the-various-kinds-of-io-blocking-…
https://luminousmen.com/post/asynchronous-programming-blocking-and-non-…
https://open-education-hub.github.io/operating-systems/Lab/IO/io-multip…
https://jhucsf.github.io/spring2023/lectures/lecture33-public.pdf
https://courses.cs.vt.edu/~cs4254/spring06/slides/IO_Multiplexing_4.pdf

De hát szerinted Tanenbaum, a Redis fejlesztői, az IBM mérnökei, neves egyetemek professzorai, ők mind, mind helikopterek, csak a libuv fejlesztője faszagyerek, mi? Baromarc.

De tudod mit, leszarom, ha nem akarsz tanulni a hibáidból hát maradj csak hülye életed végéig! És remélem, hogy a főnököd is olvassa ezt, és jó alaposan megfontolja ezután, kell-e neki ilyen idióta semmirekellő troll alkalmazott, mint Te!

A második link: https://betterprogramming.pub/internals-workings-of-redis-718f5871be84

Az Async IO fejezet alatt van az epoll megemlítve és a rajznál is az asynchronous/non-blocking kategóriába sorolja az epoll-t. Az általad hozott SZAKIRODALOM szerint tehát ha epoll-lal valósítod meg a programodat, akkor aszinkron és non-blocking lesz a program.

Pont az ellenkezőjét állítja mint amiért linkelted.

(Egyébként ennek a cikknek sincs igaza, mert a non-blocking+multiplex együtt szükségszerűen aszinkron lesz, a select+non blocking IO is az. Kevésbé hatékony, mint az epoll, de ugyanúgy aszinkron a működése. Mivel a végrehajtás sorrendje nem definiált a program által, hanem úgy lesz ahogy éppen kijön a lépés: pont ez az aszinkron kifejezésnek a definíciója.)

Disszonancia mindenképp van, mert eddig V8+libuv forráskódját akartad felhozni, mint követendő példa, most meg már csak egy jöttment honlap? Egyszerű logika, hogy attól tökéletesen függetlenül, hogy igaza van-e a libuv-nek vagy sem az "aszinkron" elnevezést illetően, ez neked egy kurva nagy belső ellentmondás.

Mi derült ki? Csak annyi, hogy valami random honlapon a saját cuccáról hazudozik valami arc?

csak a libuv fejlesztője faszagyerek, mi?

Azt azért vágod, hogy ez nem egy random honlap, hanem a libuv honlapja? Ráadásul a másik kibaszott nagy ellentmondásod itt következik: a libuv pont annak a nodejs-nek a része, aminek szálkezeléséről elég sok hozzászólást váltottunk, és most mint kiderült, pontosan úgy működik, ahogy egészen végig állítottam: network IO-ra egyetlen szálat használ epoll-lal (most direkt nem is írtam, hogy ezt aszinkronnak hívja-e vagy sem a szakirodalom), és ezen feltételezésem miatt amúgy válogatott jelzők sorával illettél.

Szerintem menj vissza JavaScript motort írni :D

most direkt nem is írtam, hogy ezt aszinkronnak hívja-e vagy sem a szakirodalom

Persze, hogy nem mered leírni, mert akkor be kéne ismerned, hogy tévedtél.

Még mindig nem mutattál ASZINKRON IO-ra példát egy szálon, helyette vergődsz itt, mint disznó a jégen, hogy a multiplexelés szinkron-e (nyilván az, hisz egyszerre csak egy fd-t tud visszaadni) csak azt tudnám, minek...

Szerintem menj vissza JavaScript motort írni :D

Egy GUI függvénykönyvtárt irok, te barom, ez annak a GUI függvénytárnak a topikja, nem egy JS motoré. Látom végleg lecsatlakoztál a valóságról.

nem mered leírni

Azért nem írtam direkt, mert nem releváns a mondatban. A mondat a nodejs egyszálú network IO-járól szólt, amit kb. 50 hozzászóláson át habzó szájjal tagadtál.

egyszerre csak egy fd-t tud visszaadni

Hadd segítsek, többet tud visszaadni: https://man7.org/linux/man-pages/man2/epoll_wait.2.html "descriptors in the interest list that have some events available.  Up to maxevents are returned by epoll_wait()"

nem egy JS motoré

Ezt arra írtam (szarkasztikusan), ha átjött volna, hogy többször is a JS motorok szakértőjének nevezted magad, meg hogy írjak én is JS motort, ha merek. Ami úgy főleg furcsa, hogy végig arra verted magad, hogy nodejs több szálon kezeli a network IO-t, aztán kiderült, hogy nagyon nem. Vagy már elfelejtetted ezeket:

"Meséld már el kérlek, ugyan mégis hogy csinál 10 network kérést párhuzamosan a JS motor, ha csak egyetlen szállal rendelkezik össz-vissz?
Kíváncsian hallgatlak! (Popcorn bekészít)"

Nos kiderült, hogy a nodejs+libuv az pont így csinál egy szálon egyszerre 10 network kérést, ahogy én azt végig konzisztensen állítottam.

Szerintem ne ásd magad mélyebbre.

Egy GUI függvénykönyvtárt irok

A GUI függvénykönyvtáradhoz amúgy továbbra is sok sikert kívánok (és ezt meg őszintén írom.)

Kedves Trollok!

Minekutána beismertétek már a tévedéseteket, abba lehet hagyni a hisztit.

Nem én tehetek róla, hogy hülyét csináltatok magatokból, nem én mentem utánnatok mindenféle topikokba, hanem ti jöttetek az ÉN topikomba bolondot csinálni magatokból.
Amit itt kaptatok érte tőlem, arra van egy nagyon szép régi magyar népi mondás: "Aki elmegy kurvának, az ne sírjon, ha basszák."

Kedves Mindeki más!

A többi forumozótól ezúttal is elnézést kérek, hogy etettem a trollokat, akik eltérítették az SMGUI-ról szóló eszmecserét.

@bzt: szerintem az SMGUI bejegyzést tedd át inkább a blog szekcióba! Akár átmásolva az eredeti bejegyzést + a frissítéseket.

Úgy látom itt már kezd elveszni a sok más téma miatti hozzászólások között a lényeg.

A multithreading, multiprocessing témában meg lehetne valami fórumbejegyzés ahol mehet a flame!

Félreértés ne essék! Nem akarok önjelölt moderátort játszani, csak sajnálnám, ha az eredeti téma "elveszne" a sok irreleváns hozzászólás miatt. Ahogy végiggörgetem a témát már rég nem az SMGUI-ról szólnak a hozzászólások.

@másik oldalnak: én ugyan nem vagyok programozó, viszont nagyon sokat foglalkozom programozással, főként programozási nyelvekkel. Érdekel minden, ami ezzel kapcsolatos. Véleményem szerint, itt jelen esetben az a helyes amit bzt ír, teszi ezt akármilyen stílusban is. Hazai pályán akartátok megszorongatni, amit nem is értek. Ráadásul olyan dolgokkal, amikkel kapcsolatban felületes a tudásotok vele szemben.

A jelenlegi ismereteim és az itt lévő hozzászólások tartalma - és nem a stílusa - alapján fogalmazódott meg bennem ez a vélemény. És ez az én véleményem, amivel nyilvánvalóan nem kell egyetérteni.

Béke!

Totális elbeszélés van egymás mellett, és a részt vevő feleknek nincs is igényük arra hogy közös nyelvet alakítsanak ki. Ezért mondom, hogy a fejlesztőknek mennyire fontosak a soft skillek, és hogy sajnos ennek hiánya miatt nem szabad a legtöbb fejlesztőt ügyfelek vagy üzleti szereplők közelébe engedni.

a részt vevő feleknek nincs is igényük arra hogy közös nyelvet alakítsanak ki.

Való igaz, a trollok csak kötekedni próbálnak, minden áron. Eleve hogy várhatnád el a közös nyelvet velük, ha még csak nem is az adott témáról beszélnek, hanem tök másról?

Ezért mondom, hogy a fejlesztőknek mennyire fontosak a soft skillek, és hogy sajnos ennek hiánya miatt nem szabad a legtöbb fejlesztőt ügyfelek vagy üzleti szereplők közelébe engedni.

Elég durva túlzás lenne ez a ricpet gyereket egy fizető ügyfél számba venni...

Akikkel itt szót váltottunk, azok sem nem ügyfelek, sem nem üzleti szereplők, sem nem komoly szakemberek, hanem az internetes pöcegödör legeslegalja, a trollok. Velük nyilvánvalóan nem olyan stílusban kell "társalogni", amit hogy egy fizető ügyféllel vagy komoly szakemberrel szokás, mert azt egyszerűen nem értik. Ezt ricpet ékesen demonstrálta többször is ebben a topikban, mikor brahiból megpróbáltam komoly szakemberként megszólítani. Nem értette.

Szerintem az nem troll, aki szakmai állításokat igyekszik tenni, és főleg nem az, aki hajlandó belátásra. Már többször említettem, hogy én elismerem a munkád, örülök ha pörög a topikod eredeti témája stb. De attól még hozzászólni szabad, és szerintem nem ilyen stílusban illene válaszolnod.

Csakis magadra vess!

Ha azt akarod, hogy az emberek illő stílusban beszéljenek veled, akkor neked is tessék illő stílusban beszélni! Az nem járja, hogy
1. odapofátlankodsz egy topikba és másról kezdesz pofázni
2. "súlyos tévedés"-nek titulálsz egy tényekkel megalapozott állítást (miközben nem mellesleg iszonyú faszságot állítasz, ráadásul mindenféle bizonyíték nélkül)
3. követelőzöl, hogy neked aztán tényleg mindenki csak úgy higgyen el mindent bemondásra, csak mert állítólag te szartad a spanyolviaszt vagy mi
4. még azután is paraszt módon kötözködni próbálsz, hogy beismerted a tévedésed

Az meg már tényleg csak hab a tortán, hogy mindezek után van még bőr a képeden megpróbálni felróni a többiek stílusát. Hát, disztingvált válaszom az, hogy lófasz a seggedbe, nem vagy Te abban a helyzetben, hogy bárki stílusát is számon kérhetnéd.

P.S: a 1., 2. és 3. pont alól még az sem ment fel, hogy utólag beismerted a tévedésed. Kulturált ember ilyent eleve nem csinál, csak egy troll.

Az tetszik, hogy minimalista a GUI lib. Akár használnám is, ha ilyesmi kellene és nem találnék jobbat.

A baj az, hogy bzt olyan állításokat tesz, amik tényszerűen nem helyesek, ami felett néhányan nem tudunk elsiklani. Például valóban lehet ezt a GUI libet több szálról használni és ha _nagyon figyelsz_, akkor valóban jól is fog működni. De az az állítás már nem igaz, hogy bármit csinálhatsz, mert például a 0 zárt listák arrayben tárolva nem feltétlenül működnek jól több szálról piszkálva egyszerre. Ha csak az értékeket írod felül és a platformod garantálja ezeknek az atomiságát (mint pl x86-on), akkor az jó lesz. De ha a szerkezetet akarod megváltoztatni, például betenni a listába egy új gombot, akkor érhetnek meglepetések. Persze ha csinálsz egy másolat tömböt és utána atomi módon átírod a pointert, akkor jó lesz. De akkor meg nagyon kell figyelni, hogy az előző pointeren még a másik szál iterálgathat miután te már átírtad a pointert és akkor azokat a tömböket nem szabadíthatod fel ameddig nem garantált, hogy a másik szál már végzett. Ez csak egy példa, a lényeg az, hogy a többszálúság ezernyi problémát hoz, amit nem lehet lerázni azzal, hogy nem kell figyelni semmire mert működik. Amit lényegében bzt írt.

És ha egy többszálú program nem helyes, akkor az működhet úgy, hogy 1000000x lefut jól, aztán 1000001. alkalommal krashel vagy pláne félrevezető dolgot csinál. De még 1E-9-ig is elemehet a hibázás valószínűsége, tehát sokszor futtatni és úgy bizonyítani sem opció. Emiatt az, hogy lefuttattam vagy teszteltem, az nem bizonyít semmit, ezért kell a modellt (példul egy szabályrendszert amit minden kód betart) bizonyítani matematikailag, hogy helyes. Ez baromi nehéz és emiatt a GUI keretrendszerek inkább úgy döntöttek, hogy egyszálúak lesznek, ami meglepő módon teljesítmény szempontból is ideális ugyanis a GUI "widget tree" kezelése (ami HTML esetén a HTML tree, amit a böngésző developer tools-ban is megnézhetsz) simán elmegy egyetlen szálon 60FPS-sel minden mai számítógépen. Tehát a többszálúságra nincsen valódi igény. Arra van igény, hogy a várakozással járó műveleteket külön szálon futtassuk, ez jogos, és ténylegy kényelmes, hogy ha mondjuk a progress bar-t frissíthetjük a háttérszálról közvetlenül. Ez jópofa feature, és lájkolom, akár még használnám is ha nem találnék jobbat.

>Véleményem szerint, itt jelen esetben az a helyes amit bzt ír

Tévedni emberi dolog.

A baj az, hogy bzt olyan állításokat tesz, amik tényszerűen nem helyesek

Meg a maci faszát nem helyesek, csak a te értelmi színvonaladon nem vagy képes ezt felfogni, és az sem segít, hogy még a magyar nyelvű szövegértelésre is képtelen vagy.

0 zárt listák arrayben tárolva nem feltétlenül működnek jól több szálról piszkálva egyszerre. ... De ha a szerkezetet akarod megváltoztatni, például betenni a listába egy új gombot, akkor érhetnek meglepetések.

Tényleg, ülj vissza az iskolapadba, és tanulj már magyar nyelvű szövegértést, mert siralmas, amit leművelsz. A kisfiam jobban tud olvasni, mint Te.
Ha több szálon akarod matatni a layout-ját, az a Te dolgod, Neked kell a szemaforokra odafigyelni. Maga az SMGUI sohasem ad hozzá vagy vesz el ebből a listából.

Egyszerűen szánalmas, hogy egy ilyen egyszerű mondat is meghaladja az értelmi képességeidet.

Amit lényegében bzt írt.

Sosem írtam ilyent, de még csak hasonlót sem. Komolyan ennyire szar vagy szövegértésből?

akkor azokat a tömböket nem szabadíthatod fel

Nincs is memóriafoglalás, Te istenbarma, mégis miket hordasz itt össze-vissza? Mutasd meg a demo.c vagy mondjuk a widgets.c példában hol van bármiféle allokáció!
Na, gyerünk, linkeld csak szépen ide, hol történik az állítólagos foglalás és felszabadítás, amirőt itt pofázol!

Ha nem vagy képes belinkelni, az azt jelenti, hogy a TE programod foglalta le a memóriát, a TE programod kezelte szarul, és a TE kódodban van hiba, az én függvénykönyvtáramnak semmi köze a TE programod hibájához!

ezért kell a modellt (példul egy szabályrendszert amit minden kód betart) bizonyítani matematikailag, hogy helyes.

Hol van a Windows GDI helyességének a matematikai bizonyítása, seggarc? Tessék idelinkeni, ha ilyen kijelentést teszel! Nem fogod tudni, mert nem létezik, csak jár a pofád, de nem tudom, minek.

Tehát a többszálúságra nincsen valódi igény.

A baj az, hogy olyan állításokat teszel, amik tényszerűen nem helyesek. MINDIG van igény a view és controller külön szálakon való futtatására. Valódi igény.

(ami HTML esetén a HTML tree, amit a böngésző developer tools-ban is megnézhetsz) simán elmegy egyetlen szálon

A baj az, hogy olyan állításokat teszel, amik tényszerűen nem helyesek. Pont hogy a DOM renderelés párhuzamosan, több szálon zajlik, az ÖSSZES modern böngészőben. Ezért is kellett beiktatni a DomContentLoaded event-et, mert az már nem elég, ha a HTML aljára rakod a script-et (ha valóban egy szálon történne, ahogy állítod, akkor eleve nem is lenne szükség ilyen eventre).

De most komolyan, ez most valami mazochista perverzió nálad, hogy folyamatosan egyre nagyobb hülyét próbálsz csinálni magadból? Már eddig is iszonyúan le lettél oltva, minek jössz vissza újabb pofonért?
"Venator, venator..." vagy mi? (Egyáltalán, tudod mi ez az idézet?)

Szerkesztve: 2024. 07. 24., sze – 19:44

További újdonságok

- lett egy UI_DONE flag, ezt az SMGUI minden frissítésnél törli. A custom widgetek arra használhatják, ami akarják (például a file pickernek megadható filter, és ha a filternek megfelelő fájlra kattintanak, akkor beállítja)
- lett külön UI_NOSHADOW flag a mezőknél. Eddig a keretet lekapcsolva eltűnt az árnyék is, most már külön-külön is lehet kapcsolni őket.
- a témába bekerült az árnyék színe, úgyhogy mostantól ez is személyreszabható. Érdemes alacsony alpha-jú színt megadni neki, alapból 0x3f000000.

Szerkesztve: 2024. 07. 28., v – 19:20

Apró, de lényeges változás.

Az ui.h behúzható fejléc és implementációs módban. Eddig a fejléc módhoz kellett az UI_HEADERONLY define, ez most kikerült, és helyette az implementációs módhoz kell ezentúl az UI_IMPLEMENTATION define. Az ok csak annyi, hogy így csinálja a többi stb stílusú fejléckönyvtár is.

Emiatt a példakódokban nem elég már az include, hanem kell még egy define. Viszont hosszú távon szerintem megéri (ha úgy tetszik "szabványosabb" így). Az fontos, hogyha kézzel konfiguráljuk a modulokat, akkor a define-nak a modulok UTÁN, közvetlenül az include előtt kell lennie.

Illetve találtam egy bugot a packed PNG skin esetén, amikor az atlaszinformáció tömörítetlenül van tárolva. A mellékelt példa skin.png-ben tömörített, így eddig nem tűnt fel, mindenesetre javítva.