Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailemVyřešeno mysql++ a multithread aplikacia

Zdravim.
Nema niekto skusenosti s mysql++ a viac vlaknovymi aplikaciami v c++? Vkladna su vytvarane a riadene prostriedkami pthread. Mam aplikaciu, ktora je tvorena viacerymi vlaknami a tie sa delia do dvoch skupin:

1. reader vlakna (viacero vlakien) - pracuju s globalnymi datami, ziskanymi z DB (iba ich citaju)
2. writer vlakno (jedno vlakno) - precita data z DB a ulozi ich do globalnych premennych

Tieto vlakna su vzajomne synchronizovane cez mutexi z kniznice pthread. Synchronizacia prebieha v nasledovnych etapach:

1. writer uzamkne data pre citanie vlaknami (reader), ktore este nezacali svoju cinnost, aby mohol obnovit data nacitanim z DB.
2. caka na vlakna (reader), ktore uz zacali svoju cinnost kym ju nedokoncia.
3. ked nie su ziadne pracujuce vlakna (reader), obnovi data z DB
4. odomkne globalne data (prebudi vsetky cakajuce vlakna - reader)
5. uspi sa na definovany casovy interval.

Problem nastava, ked caka na vlakna aby dokoncili svoju cinnost. Vzdy sa jedno vlakno zastavy asi na operacii mysql::update, ktora je poslednou operaciou pred ukoncenim cinnost vlakna a predat riadenie vlaknu writer. Vsetky vlakna bezia v cykle, cize tak ako boli vytvorene pri spusteni aplikacie, tak existuju neustale po celu dobu aplikacie az po jej skoncenie, pricom cakaju na poziadavky od externeho zdroja.

Ak sa uz niekto stretol s podobnym problem zaujimalo by ma ako vyriesil.

Za kazdu prinosnu odpoved vopred dakujem.

Předmět Autor Datum
Pravdepodobne nastane deadlock pri zamykaní mutexov, do úvahy prichádza aj vyhladovanie vlákna (star…
los 09.07.2011 09:08
los
Zdravim. Nie je to celkom moja prva aplikacia s vlaknami, len jazyk sa zmenil, v ktorom som ich vyvi…
PeterKD 09.07.2011 17:39
PeterKD
Neviem, podľa ktorého vzoru si to implementoval, ale nemáš to dobre. Vo funkcii dataThread najskôr o…
los 09.07.2011 19:33
los
Ten priklad bol povodne takto: Thread Reader: ThreadWriter: mutex_lock(mutex); mutex_lock(mutex); w…
PeterKD 09.07.2011 22:48
PeterKD
Chyba nie je priamo v tom, že používaš dva mutexy. Problém je len to, že tie mutexy nezamykáš/neodom…
los 10.07.2011 09:32
los
Tak upravil som to na ten rwlock, nastavil som precedenciu na PTHREAD_RWLOCK_PREFER_WRITER_NONRECURS…
PeterKD 11.07.2011 12:44
PeterKD
Skontroluj návratové hodnoty každého volania funkcií, ktoré pracujú s rwlockom. Ešte môžeš skontrolo…
los 11.07.2011 20:28
los
Vdaka za pomoc. Vyzera, ze to mal na svedomi pristup k DB. Jedno connection pre vsetky vlakna nestac… poslední
PeterKD 12.07.2011 11:38
PeterKD

Pravdepodobne nastane deadlock pri zamykaní mutexov, do úvahy prichádza aj vyhladovanie vlákna (starvation). Bez ukážky implementácie, na ktorej by bolo vidieť, ako pracuješ s mutexami, sa konkrétnejšie poradiť nedá.

S takýmito problémami zápasí asi každý, kto začína s viacvláknovým programovaním. Pohľadaj si na webe niečo o synchronizácii pre "multiple readers single writer" - ide o častý prípad, ktorý sa rieši pomocou read-write locku (v Pthreads je to pthread_rwlock_t).

Zdravim.
Nie je to celkom moja prva aplikacia s vlaknami, len jazyk sa zmenil, v ktorom som ich vyvijal a nemusel som riesit taketo hromadne zamykanie. Multiple readers single writers som uz pozeral a mam to naprogramovane podla daneho vzoru. Myslim, ze nema byt na tom co zle, ale mozno som nieco prehliadol.

V prilohe posielam zjednoduseny model zamykania a odomykania, ktory aj funguje, ale je to len model, v aplikacii to uz niekde viazne. Vo hviezdickovych komentaroch je cast kodu, kde si myslim, ze to robi problem. Konkretne funkcia dataThread 60 - 63 riadok. Je to operacia ktora sa pri jednom vlakne vykona ako posledna a vlakno sa ani neodomkne a potom ostatne vlakna cakaju kedze su uzamknute.

Neviem, podľa ktorého vzoru si to implementoval, ale nemáš to dobre. Vo funkcii dataThread najskôr odomykáš writerMutex a až potom zamykáš readerMutex - to je nesprávne, pretože sa ti môže stať, že medzitým refreshThread nastaví hodnotu writer na true a prečíta hodnotu readers ako rovnú nule.

Ďalšia vec, hoci je to len príklad - vlákna by si mal na konci programu ukončiť trochu slušnejším spôsobom (použiť join). Namiesto trápenia sa s mutexami by som na tvojom mieste použil ten pthread_rwlock_t.

Ten priklad bol povodne takto:

Thread Reader:                                 ThreadWriter:
mutex_lock(mutex);                             mutex_lock(mutex);
while (is_writer) cond_wait(w_cond, mutex);    while (count != 0) cond_wait(r_cond, mutex);
count ++;                                      is_writer = TRUE;
mutex_unlock(mutex);                           mutex_unlock(mutex);
…                                              …
// reading                                     // writing
…                                              …
mutex_lock(mutex);                             mutex_lock(mutex);
count --;                                      is_writer = FALSE;
if (count == 0) cond_signal(r_cond);           cond_signal(w_cond);
mutex_unlock(mutex);                           mutex_unlock(mutex);

Je to priblizne to iste az na to, ze ja tam mam namiesto jodneho mutexu dva co je asi ta chyba, ktoru si popisoval a is_write = true by malo byt asi pre while (count != 0) cond_wait(r_cond, mutex).

Zdroj:http://www2.fiit.stuba.sk/~cernans/pp/pp_texts/pp_ prednaska_5_synchronizacia.pdf

Tie vlakna som neukoncoval (teda necakal som na ne v hlavnom vlakne cez join) ako pises, pretoze aplikacia ma bezat nonstop. Snazil som sa zachytit kill signal a ukoncovat aplikaciu tak, ale neustale mi to tam havaruje, tak som to odlozil na neskor. Zatial potrebujem aby sa mi to nezaseklo ako teraz a potom ostatne doladim.

Da sa s tym pthread_rwlock_t robit aj podmienene zamykanie podobne ako tu? Aj ked neviem ci to vyriesi moj problem pretoze k odomknutiu jodneho vlakna nedoslo ako som pisal, ale mozem vyskusat toto a uvidim co sa stane.

Chyba nie je priamo v tom, že používaš dva mutexy. Problém je len to, že tie mutexy nezamykáš/neodomykáš tak, ako by si mal. V predchádzajúcom príspevku som ti napísal, aký problém tam môže nastať (resp. nastane) - následkom toho prestane celá synchronizácia plniť svoj účel.
BTW: To is_writer = TRUE by naozaj malo byť pred tým cyklom - je to uvedené aj v tom zdroji na ďalšom slajde.

RW Lock je určený presne na takýto účel, takže nevidím dôvod pokúšať sa to implementovať vlastným spôsobom. Len pre upresnenie, v tomto kóde nie je žiadne podmienené zamykanie, ale čakanie na splnenie podmienky. Ešte lepšie povedané, ide o blokujúce čakanie na signál, ktoré je zabezpečené pomocou cond_wait (spolu s cond_signal).

Tak upravil som to na ten rwlock, nastavil som precedenciu na PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, a ked sa tie vlakna opat stretli znovu to zatuhlo, writer sa neodomkol.

Synchronizujem to nasledovne:

Writer:                     Reader:
  pthread_rwlock_wrlock       pthread_rwlock_rdlock
  ...                         ...
  pthread_rwlock_unlock       pthread_rwlock_unlock

Co moze ovplyvnit spravanie rwlocku? Uz zacinam byt z toho dost zufali. Na modelovej aplikacii mi to samozrejme funguje, co je mi ale na dve veci.

Skontroluj návratové hodnoty každého volania funkcií, ktoré pracujú s rwlockom. Ešte môžeš skontrolovať, či nie je volanie SQL príkazu blokované na strane databázy (SHOW PROCESSLIST).

Ďalšie konkrétne rady už nemám, len všeobecne: musíš presne určiť miesto, v ktorom vlákna zatuhnú, a zanalyzovať, prečo vykonávanie nepokračuje ďalej. Ladenie takýchto chýb vo viacvláknových aplikáciách je náročné, takže želám veľa šťastia.

Zpět do poradny Odpovědět na původní otázku Nahoru