Analiza programelor cu mai multe fire

Avem o bază de cod care are vechime de câțiva ani și toți dezvoltatorii originali au plecat de mult. Folosește multe, multe fire, dar fără design aparent sau principii arhitecturale comune. Fiecare dezvoltator avea propriul stil de programare multithreaded, astfel încât unele fire comunică între ele folosind cozi, unele date de blocare cu mutexuri, unele blocate cu semaphore, unele utilizează mecanisme IPC ale sistemului de operare pentru comunicațiile intra-proces. Nu există nicio documentație de proiectare, iar comentariile sunt rare. Este o mizerie și se pare că ori de câte ori încercăm să refacem codul sau să adăugăm noi funcționalități, introducem blocări sau alte probleme.

Deci, știe cineva despre orice instrumente sau tehnici care ar ajuta la analiza și documentarea tuturor interacțiunilor dintre fire? FWIW, codul de bază este C ++ pe Linux, dar aș fi interesat să aud despre instrumente pentru alte medii.


Actualizați

Apreciez răspunsurile primite până acum, dar speram să fie ceva mai sofisticat sau mai sistematic decât sfatul care este în esență "să adăugați mesaje de jurnal, să dați seama ce se întâmplă și să remediați acest lucru". Există o mulțime de instrumente acolo pentru analizarea și documentarea fluxului de control în programele cu un singur filet; nu este nimic disponibil pentru programele multi-threaded?


See also Debugging multithreaded applications

0
fr hi bn

7 răspunsuri

Un lucru pe care trebuie să-l țineți cont de utilizarea log4net sau a unui instrument similar este faptul că modifică calendarul aplicației și poate adesea să ascundă condițiile de rasă de bază. Am avut un cod slab scris pentru a depana și a introdus logarea, iar acest lucru a eliminat efectiv condițiile de rasă și de blocare (sau a redus foarte mult frecvența lor).

0
adăugat

M-aș concentra pe blocările de memorie partajată mai întâi (mutexurile și semaphorele), deoarece acestea sunt cel mai probabil să provoace probleme. Uită-te la care stat este protejat de încuietori și apoi determina care stare este protejată de mai multe încuietori. Acest lucru vă va oferi un sentiment de potențiale conflicte. Uită-te la situațiile în care codul care deține o blocare apelează la metode (nu uitați metodele virtuale). Încercați să eliminați aceste apeluri acolo unde este posibil (prin reducerea timpului de blocare).

Având în vedere lista mutexelor care sunt păstrate și o idee grosolană a stării pe care o protejează, se atribuie o ordine de blocare (adică mutexul A ar trebui să fie întotdeauna luat înainte de mutexul B). Încercați să impuneți acest lucru în cod.

Vedeți dacă puteți combina mai multe încuietori într-una dacă concurența nu va fi afectată negativ. De exemplu, dacă mutexul A și B par a fi blocați și o schemă de comandă nu este ușor de făcut, combinați-le inițial cu o singură încuietoare.

Nu va fi ușor, dar am pentru simplificarea codului, în detrimentul concurenței pentru a obține o manevră a problemei.

0
adăugat

Investește într-o copie a VTune și instrumentele de profilare a firelor. Acesta vă va oferi atât un sistem cât și o vizualizare la nivel de sursă a comportamentului firului. Cu siguranță nu va fi cazul pentru autodocumentul pentru dvs., dar ar trebui să fie un real ajutor în cel puțin vizualizarea a ceea ce se întâmplă în diferite circumstanțe.

Cred că există o versiune de încercare pe care o puteți descărca, deci merită să faceți asta. Am folosit doar versiunea Windows, dar uitandu-ma la pagina de web VTune are si o versiune Linux.

0
adăugat
L-am luat pe VTune pentru o rotire ... si am descoperit ca preferam profilele lui Shark din Apple mai bine cand gasesc interfata si iesire pentru intuitiv si drept. Cei doi cenți.
adăugat autor paxos1977, sursa

Nu vă pot ajuta UML aici?

Dacă inversați-vă baze de cod în UML , atunci ar trebui să puteți desena diagrame de clasă care să arate relațiile între clasele tale. Pornind de la clasele ale căror metode sunt punctele de intrare a firului, ați putea vedea care thread utilizează clasa. Bazându-mă pe experiența mea cu Rational Rose , acest lucru se poate realiza prin tragere și plasare; dacă nu există nici o relație între clasa adăugată și cea precedentă, atunci clasa adăugată nu este utilizată direct de firul care a început cu metoda pe care ați început să o folosiți. Acest lucru vă va oferi sugestii privind rolul fiecărui fir.

Acest lucru va afișa, de asemenea, "obiectele de date" care sunt partajate și obiectele care sunt specifice firului.

Dacă desenați o diagramă de clasă mare și eliminați toate "obiectele de date", atunci ar trebui să aveți posibilitatea să structurați această diagramă ca nori, fiecare nori fiind un fir - sau un grup de fire, cu excepția cazului în care cuplarea și coeziunea bazei de coduri îngrozitor.

Aceasta vă va oferi doar o parte din puzzle, dar ar putea fi de ajutor; Sper ca codul dvs. să nu fie prea noros sau prea "procedural", caz în care ...

0
adăugat

În Java, aveți opțiuni, cum ar fi FindBugs (pentru analiza bytecode statică), pentru a găsi anumite tipuri de sincronizări incoerente sau numeroși analizatori dinamici de fir de la companii precum Coverity, JProbe, OptimizeIt etc.

0
adăugat

Aceasta este o problemă foarte dificilă pentru uneltele automate. Poate doriți să consultați verificarea modelului codul dvs. Nu așteptați rezultate magice: damele de model sunt foarte limitate în cantitatea de cod și numărul de fire pe care le pot verifica în mod eficient.

Un instrument care ar putea funcționa pentru dvs. este CHESS (deși, din păcate, este numai din Windows). BLAST este un alt instrument destul de puternic, dar este foarte greu de utilizat și nu se poate ocupa C ++. Wikipedia afișează, de asemenea, STEAM , despre care nu am mai auzit până acum, dar sună cum ar putea să funcționeze pentru dvs.:

StEAM este un model de verificare pentru C ++. Detectează blocările, defectele de segmentare, variabilele din interval și buclele neterminate.

În mod alternativ, probabil că ar ajuta mult să încercați să convertiți codul spre un număr mic de scheme de sincronizare bine definite (și, de preferință, la nivel înalt). Amestecarea încuietori, semafore și monitoare în aceeași bază de coduri solicită probleme.

0
adăugat

Ca punct de plecare, aș fi tentat să adaug mesaje de urmărire la punctele strategice din cadrul aplicației. Acest lucru vă va permite să analizați modul în care firele dvs. interacționează fără pericolul ca actul de observare a firelor să-și schimbe comportamentul (cum ar fi cazul depanării pas cu pas). Experiența mea este cu platforma .NET și instrumentul meu preferat de înregistrare ar fi log4net, deoarece este gratuit, are opțiuni de configurare extinse și, dacă sunteți logic în ceea ce privește modul în care implementați logarea, nu va împiedica în mod evident performanța aplicației dvs. Alternativ, există clasa .NET construită în Debug (sau Trace) în spațiul de nume System.Diagnostics.

0
adăugat
Utilizați programul gratuit DebugView al Sysinternal împreună cu System.Diagnostics.Debug/Trace, este o modalitate excelentă de a obține informații de depanare din aplicația dvs. și este mult mai plăcută decât fereastra de ieșire a Visual Studio.
adăugat autor Rob Ringham, sursa
Spun doar: [TestFixtureSetUp] void publice ConfLog4Net() {log4net.Config.BasicConfigurator.Configure (noul TraceAppender {Layout = New PatternLayout ("[% t]% m% newline"); }
adăugat autor Henrik, sursa