From 70aad3fe1c8b38d4198aa5f32a0facddd125ee8b Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Tue, 3 Jun 2025 01:25:44 +0200 Subject: [PATCH 1/4] simple and functional --- analysis_model.h | 73 +++-------------------- main.cpp | 93 +++--------------------------- ring_buffer.h | 107 ++++++---------------------------- sensor_network | Bin 85008 -> 131280 bytes sensor_network.cpp | 141 +++++++++------------------------------------ sensor_network.h | 36 +++--------- 6 files changed, 69 insertions(+), 381 deletions(-) diff --git a/analysis_model.h b/analysis_model.h index 4b4be10..e17e11b 100644 --- a/analysis_model.h +++ b/analysis_model.h @@ -1,75 +1,18 @@ #pragma once #include -#include -/** - * Implementiert das Reader-Writer Problem mit: - * - Mehrere gleichzeitige Leser - * - Exklusiver Zugriff für Schreiber - * - Verhindert Writer-Starvation - */ class AnalysisModel { - int value = 0; // Das geteilte Analysemodell (vereinfacht) - int reader_count = 0; // Zählt aktive Leser - - // Synchronisationsprimitive - std::mutex model_mutex; // Schützt Schreibzugriffe (exklusiv) - std::mutex count_mutex; // Schützt Leserzähler - std::condition_variable no_writer; // Garantiert Fairness + int value = 0; + std::mutex mtx; public: - /** - * Lesender Zugriff - * @return Aktueller Wert des Modells - * - * Funktionsweise: - * 1. Sperrt count_mutex und inkrementiert reader_count - * 2. Erster Leser sperrt model_mutex (blockiert Writer) - * 3. Entsperrt count_mutex während des Lesens - * 4. Liest Wert - * 5. Sperrt count_mutex zum Dekrementieren - * 6. Letzter Leser entsperrt model_mutex und benachrichtigt Writer - */ int read() { - std::unique_lock count_lock(count_mutex); - reader_count++; - - // Erster Leser sperrt für Writer - if(reader_count == 1) { - model_mutex.lock(); - } - count_lock.unlock(); - - // Kritischer Abschnitt (Lesen, kann parallel erfolgen) - int result = value; - - count_lock.lock(); - reader_count--; - // Letzter Leser gibt für Writer frei - if(reader_count == 0) { - model_mutex.unlock(); - no_writer.notify_one(); - } - - return result; + std::lock_guard lock(mtx); + return value; } - /** - * Schreibender Zugriff - * @param new_value Neuer Wert für das Modell - * - * Funktionsweise: - * 1. Sperrt model_mutex (exklusiver Zugriff) - * 2. Schreibt neuen Wert - * 3. Wartet bis alle Leser fertig sind (Starvation Prevention) - */ - void write(int new_value) { - std::unique_lock lock(model_mutex); - value = new_value; - - // Verhindert Writer-Starvation - no_writer.wait(lock, [this]() { - return reader_count == 0; - }); + void write(int new_val) { + std::lock_guard lock(mtx); + value = new_val; } -}; \ No newline at end of file +}; diff --git a/main.cpp b/main.cpp index b608ad5..d13d9c2 100644 --- a/main.cpp +++ b/main.cpp @@ -1,90 +1,13 @@ #include "sensor_network.h" #include -#include -#include -#include - -// Standardkonfiguration -constexpr size_t DEFAULT_NUM_SENSORS = 3; -constexpr size_t DEFAULT_NUM_ANALYSERS = 2; -constexpr int DEFAULT_RUN_TIME = 30; // Sekunden -constexpr size_t DEFAULT_BUFFER_SIZE = 8; - -/** - * Führt die Simulation mit gegebenen Parametern aus - * @tparam N Puffergröße - */ -template -void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { - SensorNetwork network; - std::cout << "\n=== Simulation gestartet ===\n" - << "Sensoren: " << num_sensors << "\n" - << "Analysemodule: " << num_analysers << "\n" - << "Puffergröße: " << N << "\n" - << "Laufzeit: " << run_time << "s\n\n"; - - network.start(num_sensors, num_analysers); - std::this_thread::sleep_for(std::chrono::seconds(run_time)); - network.stop(); - - std::cout << "\n=== Simulation beendet ===\n"; -} - -/** - * Liest Benutzereingabe mit Standardwert - * @param prompt Eingabeaufforderung - * @param default_value Standardwert bei leerer Eingabe - * @return Eingegebener oder Standardwert - */ -size_t get_input(const std::string& prompt, size_t default_value) { - std::cout << prompt << " [" << default_value << "]: "; - std::string input; - std::getline(std::cin, input); - - // Verwende Standardwert bei leerer Eingabe - if(input.empty()) return default_value; - - // Konvertiere Eingabe - try { - return std::stoul(input); - } catch(...) { - std::cout << "Ungültige Eingabe. Verwende Standardwert: " - << default_value << "\n"; - return default_value; - } -} int main() { - std::cout << "=== Sensornetzwerk-Simulation ===\n" - << "(Leere Eingabe verwendet Standardwerte)\n"; - - // Interaktive Konfiguration - size_t num_sensors = get_input("Anzahl Sensoren", DEFAULT_NUM_SENSORS); - size_t num_analysers = get_input("Anzahl Analysemodule", DEFAULT_NUM_ANALYSERS); - int run_time = static_cast( - get_input("Laufzeit (Sekunden)", DEFAULT_RUN_TIME) - ); - size_t buffer_size = get_input("Puffergröße", DEFAULT_BUFFER_SIZE); - - // Starte Simulation basierend auf Puffergröße - switch(buffer_size) { - case 8: - run_simulation<8>(num_sensors, num_analysers, run_time); - break; - case 16: - run_simulation<16>(num_sensors, num_analysers, run_time); - break; - case 32: - run_simulation<32>(num_sensors, num_analysers, run_time); - break; - default: - std::cout << "Nicht unterstützte Puffergröße. Verwende Standard (" - << DEFAULT_BUFFER_SIZE << ")\n"; - run_simulation( - num_sensors, num_analysers, run_time - ); - } - - std::cout << "Simulation erfolgreich abgeschlossen.\n"; + SensorNetwork<8> network; + std::cout << "Starting simulation...\n"; + network.start(2, 2); // 2 sensors, 2 analysers + + std::this_thread::sleep_for(std::chrono::seconds(30)); + network.stop(); + std::cout << "Simulation finished\n"; return 0; -} \ No newline at end of file +} diff --git a/ring_buffer.h b/ring_buffer.h index ee992c8..4e7a0ff 100644 --- a/ring_buffer.h +++ b/ring_buffer.h @@ -1,104 +1,33 @@ #pragma once -#include -#include +#include #include #include -/** - * Thread-sicherer Ringpuffer mit fester Größe - * @tparam N Größe des Puffers (muss > 1 sein) - * - * Implementiert das Producer-Consumer Pattern mit: - * - Mutex für exklusiven Zugriff - * - Condition Variable für blockierendes Pop - * - Überschreibt älteste Daten bei vollem Puffer - */ template class RingBuffer { - static_assert(N > 1, "Buffer size must be greater than 1"); - -private: - std::vector data; // Speicher für Elemente - size_t read_ptr = 0; // Lesezeiger (nächstes zu lesendes Element) - size_t write_ptr = 0; // Schreibzeiger (nächstes freie Position) - bool full = false; // Flag, ob Puffer voll ist - - // Synchronisationsprimitive - std::mutex mtx; // Schützt alle internen Zustände - std::condition_variable not_empty; // Signalisiert, dass Daten verfügbar sind - - // Hilfsfunktion: Zeiger mit Ringverhalten bewegen - size_t advance(size_t ptr) const { - return (ptr + 1) % N; - } + std::array data; + size_t read = 0; + size_t write = 0; + bool full = false; + std::mutex mtx; + std::condition_variable cv; public: - RingBuffer() : data(N, 0) {} - - /** - * Schreibt Wert in den Puffer - * @param value Der zu schreibende Wert - * - * Funktionsweise: - * 1. Sperrt Mutex für exklusiven Zugriff - * 2. Schreibt Wert an aktueller write_ptr - * 3. Bei vollem Puffer: Bewegt read_ptr (überschreibt ältesten Wert) - * 4. Aktualisiert write_ptr und full-Flag - * 5. Benachrichtigt einen wartenden Consumer - */ void push(int value) { - std::unique_lock lock(mtx); - - // Schreibe Wert - data[write_ptr] = value; - - // Überschreibe ältesten Wert bei vollem Puffer - if(full) { - read_ptr = advance(read_ptr); - } - - // Zeiger aktualisieren - write_ptr = advance(write_ptr); - full = (write_ptr == read_ptr); - - // Benachrichtige einen wartenden Consumer - not_empty.notify_one(); + std::lock_guard lock(mtx); + data[write] = value; + write = (write + 1) % N; + if (full) read = (read + 1) % N; + full = (write == read); + cv.notify_one(); } - /** - * Liest Wert aus dem Puffer (blockierend) - * @return Der gelesene Wert - * - * Funktionsweise: - * 1. Sperrt Mutex - * 2. Wartet mit Condition Variable bis Daten verfügbar - * 3. Liest Wert an read_ptr - * 4. Aktualisiert read_ptr und full-Flag - * 5. Gibt Wert zurück - */ int pop() { std::unique_lock lock(mtx); - - // Warte bis Daten verfügbar (verhindert Busy Waiting) - not_empty.wait(lock, [this]() { - return !is_empty(); - }); - - // Lese und aktualisiere Zustand - int value = data[read_ptr]; - read_ptr = advance(read_ptr); + cv.wait(lock, [this]{ return full || write != read; }); + int val = data[read]; + read = (read + 1) % N; full = false; - - return value; + return val; } - - // Prüft ob Puffer leer ist - bool is_empty() const { - return !full && (read_ptr == write_ptr); - } - - // Prüft ob Puffer voll ist - bool is_full() const { - return full; - } -}; \ No newline at end of file +}; diff --git a/sensor_network b/sensor_network index a918fbc171ebbd4db0f619bcea1b551b07d61c64..9d99c4256d2f0ea811196ebf2e42a31732cfb6f5 100755 GIT binary patch literal 131280 zcmeFa4_sA6`aga^P%;&CwM@-!riNt({tN$x=B=x#@li3iR6sx>5fCo^%UtqL3lT-8 zt+iIxnoH#xSsA%z_-BP&D{8H%tf;ImYDHy5<#vDXXXcr6&OP^@D_XnT@AdWU;``3? zJoC)VGtV)YU>8sfkp7Nr`7hZIdAruf=KYw0O;-U7)oDKMa3L z&Wcejz{I66LMAmLQ@&@IZ^dpbr%;tnNcrrp4Gzgss71*%u}YyDI@p5+y) zdM0qb_4}oO6%U;)=?Yan{}1_;iCJ|};BL?+ae21=#|6|dN-M~Al8aIIUNbRK3oX>D zNJQ~Nv=EU#i)#_eX~iemj`*YQp!{3X#t$9$@H;Vc=3etk-%0H*>i_eMip#SyXAK^B zc~;tGS((`di!NIfH~6x_1N-IY^y{y+N4|^kM{d#ze-XV$jET8=kQNpdfA!2Bk0cW> z8h@AI?^68H)enD{JcuPV3rS75(h%8#+B%m;3R%eU|Qi?WJYjn0qEbeZcEG7_378&gC!| zwb^=gfI$Pv&#|Gew9y}ljtr!y3pywe{h!d&!&(`nAF|Q^iH)96IBg*PS3_4I`g9vT zt!>JE-iH2;4gDzW9H`tcZRB^@)N`LrJ@?z#`4SsDJZ#gCciPlv0Ll&IC$HJ)dD@1) z$wvRbZQ9kv#%>F2+WVG`{9`utq4COrKkHRsQ_tsZ>3WOXHPt24G#=Ac&*fU_?YZ26T+bXSt}TMUQMvbXx$#V& z4?DEiVBHI4xlwHYX{_gc)}!ojGuy2@w@caWV)#!W{V`nsgWNCUxZFYTXOa(N{d%k= zCC!M&zmygs;r#s^eHK`veG3lFz1HJ?*1`J zN$!lioP|kQ>DhDK8A<7Rc{zCr*QRPoH%ys2ak6_bxalcrgOet^Q{3rJkU_j6DJgZ) zqS)Bj{)PW1p zJm(~8E>|`yCw1=F$?ie(3f$?7s5)s`2@9l#oUD9jroFDKVx3&w*a3Md*=afR(7Xki zsp&&dnK|k11u0od;8e{X+n?H#la1~vNOg}zuR5IzrX)>{LudAnnVpljFeNW7DHCQ( zap$1ZQs$hd-C|HqS~`l!(am2ftdz8*lq~cOSs3md z3vY+xrp(G*5KEq)pP7`Jm6D&I^HTB_qxP9@ zG&5<=qD4u$>3R7%*(q6Y;K)OJKtpisW{)MGhzFscZ@l!hh8k##*CRTOWT`AIO2 z;pE)nfj8x3W^;%3kMrr!yu6gfN!jUY$fCZ5KgXi!um!p|2|b#QadCD^W)^%tb8<`) z{!ivUjXLT>SKuHeHd)>|>Dtp67p1plW%uCm@Q?hgNv(nRZG3H_klR7skHDj(Ab2Nl2TuRH8Ynmjn zCZIuXE<|aF;w8_#l+0{UQWvGrkdM)NNxCIZLAJ;>FMVEW?qZ0dW!X7mxTNKX23`5? zwA4#4rCo}_l$@vknv;rRC>2ZeR7t<)s;iO)^o!B189#RPRnw;7_rQMrV||hX`fK2f z8a*~Cw%-8L&wfLE#A4%olKm}Qi%y>seKYo#$)x`M2I{|Jjh_RIpZ)s{qGfR?c5%Y6 z6BLTSF#JpDmiR?~t&ob)&H|-1QeoQJS{tmMTZ0#hz16l_q>u{1wqQ%_9ohe{h0Y7p zf6I690>u~U2yGRoQ$)I@wuaO3A|0;%h12dnt8ph1rfubP zp5V98b|Otz2zdRNN9m54nQb-L>}95{x%*z+nVhA)#p!26x|Q}3rwh7d;*KU%`y6Sy z)V>}H6<1?_iSfK&tLPh;o?xNZ@qOJi3%&ExQctplKAPzn7JBz>Qht$z-pKk3E%a>G zQ)Hp9V|tl|K9cosu+SrTf4SU3-^+R`Ec7p!UTLAvWc@W3x`XxCTIgM#k?pOs(8n;n z-a=o-`Wr3uIM&}}q35z5jqRuU@qVU9Sm+P3{>~P90_%5J==)etw1wWt^cV|$C+m;5 z&@))S%R=w=th7&pg?=^Dr&;Llv;GVVy^!_iTIhMKXOV@zp6P`a`p>Mt%tBws`qx?L zHLPcYh5j|u%PsWo&&l@ITj=rClHO#YZ(w>9m#_L)tC8~27J4$%<1O?mrcblb9WO~e zxfXgM(~B(hdZur%(Bt<@J&g{z0i)`v(skS};+}^;+Q*}-(T1+#)he&z%t}}BVWlg- zw$hb9TItGmqD^!vTU{|GIwofQiZju9 zsusL>6CDc={c@S;ZFDNuJ0?073i>t8L|1#D#7s8PRV)%c!$jBjG(pcb(aq-~i%j(2 zkpjL7P4te62rM$uJDKQZCi*!h`Z^Q+ToZkRiQd^nFE`QE-ZZf*OmwvuPxML?U7fuX zy~;$tfCzlmnCK2g1lF497n(?mb>^Na<~Sm2BW&RF1#1udeO4F87L#;?}r!;NxHB^c8R!Y;>QbUDEKTc`dQfk;B z(vMJ@wvrmkMEZV8(-u-gp-8W$G;JL<?&?_?fT+M*RG}(u8@7M*M4?) zgn~p?5aF$#9eKeRBR|!za6~%Vs1*!IbgdZC8j_l;_!D(*ltaNRUlNm#FFq1Wk&t#XyFqONxpS9^Yf zivZ8fcW)p4+CyVg~@mVQFAi9qHZ2XEIY z)t(z+4`l!Zl13hV!D4Egp(jGF5tN4~CSBbO9B~M$*W=QIaV^KN>87YWXR=LAH z-~Z(GmT}G%#~hGBbqtd>kx8A6RMtae*OJ6WDEGKZlrhPBS2Tuz(PT6u+*5nP>owJ< zxB%G_sa}n)A-f~jRB^4Su7U@8NtCE|aTHg%lI&%Yqc)X*P^P!iE@$yACyEQ2Ab*kb zgp%j>7dI9;k5f63+Y*nxe#zTwC>$sm-YR?8q;xBHL?`?c<|nN4^>FfW4$mEPY&qx}stJyy|!d*;bglI-Y_@ z{N5KIBWWwD;;7!`qQhbJ6;;WU?j~KuUmx?Q+wi3$iqck8MUbY6zBLnGr))0dAk!D& zTW0i&kM}-;8V76{@*VKi?UV0o3S{!5@G@#Mq-oxflqyhm;!luY5+Ox`HB7l%s?~ju zwD@?Vk7pGrC&v72ZXE>=g2~xbR)$|5s=+zZ{rs(3k{|;Dq1I=&tGHGSyT!XjZA&oe zqXNaRkcM{9Ad}Ue$I(KQWnvJ|b>P*J+(03hi1Z|6p8!0|RXhQeKun`bdTh(ESVi_% zS(8kyH+xxl6`N-#;vM5j8&!`-Fw2YIx&d!emPSps!@PPeO=AF>np!JWm<$+?M$}ja zB~O8f6=%JxG_f8zYIuBp0%XL@synG(f?Vx+QHs_=l$0yc=XDLxf=cCyrodFC&RR;h z7o$FvAkCK#_lBK3WunMZ$|RSGL*d>FA-iHTFpfo%}_*FmhOcjA#4}CUqSUY4a4O*nQG!cK~ z<-$7G$*~N2eJ6+~VJm&wi9$u;&8A60W*!PdU~(}{Br5FW5@5wK7jjl2XN9>sv<@h7 zR*Fdqtt+J#R(nRlMQL&^aaKqU976W=#l-2e$5s3e42AxuKfQbJ`~l1oBz-38aL*Ut z5?!BlR~(BWYn!V%1Kgf47tF-<14+~(UubM;=el{vW5xR{WP>-G|s6TohwBi@_ z8UD~Rdd|bO!s($w!Q&d{tS@*^_1k0&KykOAe?=LpZ$FTO zzo#VeaB&oh0lnJO#500<2z(r^FaST5*5jd=6nz ziTS%U@j0yf?pzLgmLgo_nE5HSvNVwbznr}?9F3F`SVIdosi^k+6E})-8DN;?nxpYz z{ZIO;J@i7@(H4>*vaF*l0d5Coq2`ofKhTp%2{ACKo)gxi#*@r9%1~smU$$uwJbfotc8bqs|9*Xm$7o#+IURez><&484$v#){Tb^v(R$@Mu!zONt#1w^=Qfo0H3wJPYIr@@z8eDCyh5Xw{-G61 zTQGNdAx>E;P=Wd|`@A2k?cZa6+>$)F1t|eBo+n z(tROD#j*crSBHw~!wfC_a-|0`Gd8{WPN?(B8^>5J85n zGQ&p7@D69VLS_i@En$W%;fTl=o=+Lxi%(pY(0R2j9zm^tJ)t5&77IR+Ea zph}D9YEL~zR8!F3fYax;Y(V=U`Bl% zF^W4S%nWY|rsZyH6dGaF+5s<+6O8F5Vt6~mgHao!u4u<#+SjCd<9DUp3eZ2aoXfTKe4@MnM~ET_H$f zbs*et0vwK}R&ih212sL`Mc&GRR_*CUTMJmi;%AM}r0&XSlX%+2RK^SCbzZO8>BU-Z zRWjn8vYkbRmg>oRB#U9*Rkg^)%edVr)gR$Ti$c(}c>7{f~h}LiYC3i$?*Y_W}GIy7er}Y7MzpHd~nyYwKC6!vbR>G<(qYf=` zvk$eBQteqrRVrCUO%o1>jpMbV#-*#MUR?37P&hfs2cGtn-H_KeZ$dCc(5A^a*imgj zE6Y4jivs`KgT_yZT^y<+J!cWMHoViD0C~$bPL#SEo+!P3zf42utA!*aLZO!uIw8}K>OyZALK+dd zGP)gpK$MUjrjm=RxFsKQNgtvPvG<{W(3ENT(0bh9T78ISQj^FGh%~(5>ne9qfWTF@ zKia3$oC`+o*+NbOH=+GMPit3Z?IAjH0Ig50EBv?^qohBSt`%i1B;`uEX~AIUzN^|5~+y-z%IA2|X={Slm|nxnpgJP`di7K$%SO2aRBofu-n zW{N1)i28#v4WXa%Nk~Nf3lA``B8sV+^85)uPpgIg3vDN z=aZfMJ*vE($hafhB<)*`ti8*9RI8WKKEmyJDef>X5H#-D#Qa58^2XlgQID zhkx9^4moSwA7~{zQyBCY%=Vq7->A4Rqbil0Ebdz%lZ^YP5Nam*aCP(dI|Q#?-2an$ z*1wlRKOl0o=O#kSZ2#%|L{lp+b>3y2?bqQc33J>xa`27B(nH35bS_yu{Nh*0cp~nn zljdS0?hnZ{gj$fSjQcB;5Xb#BnI2(h(>Bs$BsJO{NwqPM?^`SC4 zyEo!K2O`$Ee^^ZBztU{)A!SC~CsXm}xED4z;=UJ`-Tb)!2J0h}M%|-!Aqef_elgj} z-=iuH5xLsa`8`tUyMA0lJj0{ZSprsla%Z?Pa+?+>A0m)DoP0Kgg=L_V@D)`UH>y3? zWA9YI*K&wEARMNcmvdrYQ{3KSM_70u?UC(seh)L!CULdrPAq3|LsBpAy}oA`91gSi z-3hv_8YHRscC+&JQ{FGwBq+L@0_v5v(P7?IMD7!;~K#jpwt z$amGrFjyt(QGwf2pUr%^iw!c)0L5m#vyM6uH4u9rs5{-N;O|mreHjupNMM_`DRRM; zuF?sVs@#r_M3LgA^kzI3Mz^`NKP)@)KI)wk9K0H&4ImvoOA?%oC@!(mB{q14x3v`B zMfs~eJ?Q}iEC@;x%OQ?hVv+Nz=O_3E_R?xaxxT6|q6~bV`IaczcgOq6xBdN5^rFw% z*jv*1*mhCmf5ipI=>Y+F0$ikI!g1N$DRdH{8#x|=ekb&6AtH?FdqPjg9yD0oNwyRI zQ0@6Ziq>Lxi8`Z(E%=eHL2jPUCI>IZJ^;5f=Y28~czk;K8e$GbadAKpBb z6Z*4pzZYoNq@=Kr=GGB8p_;aU9(fSq_c7I$elxq&g)<85ofY3Mq{Ti)7!H~!;_ST-LGy@c93jTR#`WAS8Wss9Gq9gW8=bTnH3@lz2h;2D#hoQ1J{o5l zAuH-z$*8Eq7!pmK$Zhd47@xYZl*3QTAvsdoRTA$IPmEDy)fFYg2qr&p^u!y&=TWa} z&waF$1M8a?kk_KO5*7o}$wqN~Uo z@s|jpNf4TVOcO8|B(4K*19%&N)C7VjM; z_r=AKz(Y#$zVXGMdG-v)3%nH9u+7=XMYOrdBTfiWJO*+)WTpBRCqx__GPd|1&XwQk zqVW(NU+f`E{DZ7g;-u0oHbQhz(COfL2 zD>5{ZdzFYDkv~PJxP6{-G3F>2tm|`}Cfx`_T>`mLEm!7qssI_H)RheL0f{BXx#3-z zMdXr64$ko~BCG_<$O9r9d4}1;Dq$E0ap*a=k{Ji2zG_c3%CRm$1|97uk5y4(wdYZ) ziB%-r)8-%y3AP*P@&4<#<4dEk3=if@p9Juw3y`OozH}VJD*Mu6(dvM{REJoHwc%QL zbgDCc`}xxUG~UifBZArJ)c`j735(HY+Nc(yY@@{2ZR2gb^kZS8i4=Q&Ho{;OLj$jQ z)K%x}KIbu*)WqE4`xI5?YvvisR+BtjZiEK>!PRMs44|#6q3z@|!Zg#2@CCL|d}joV z0b<12iPLv|MsUe^jWlKi7pg%sLV{^Vi1(9}Q5KP_%yzf=?1wXO$ zN8aK!&j>?me>+ipGgd3XJapJF{~6);$kR*@?FUiz(5J~NfoFu}bUMvZyqT7;{vK-F zUCE9z&j{2bJR?x2oW_hmZiGQtILo_K0Wl*K6=Ei|ObYMOg95~rlR`XanvNJVPYS;7 zLz6;0<=PjYV4f7VqA2T#?>i}!i3L5}&i84z?_Y*3G2|t^f=S^BCGSQ{@!#p@-)+%>ai4NZ%P-94mc+)LA1lzV!WG4+s=O8^gp%HS!hHs8+{VMMxWu{ zp_w+?0a3Qmr~|eUHyxi~Q8pTiGcbP}opkIiTSw7hEXZ@P`12WlR~M0h463g$G)CY; zK^Kdr3-m#_Oc2F5Tv&#D7>XUJAUwaYkknYk1yS(zoJy2l?T`!gGSVcp=v%e_ehD_= zvH7Uj+Vx$nKd@f~)Bk?8{sGp|!93-qIR9vR0ePC~DXSsMo^q~eb--v^?+_*w(G*1| z$bQj;l>%U<+pOD_!>NI~Kh;JK)K#LN zeOB*B=qVn3pk7@_64DoE!}m>NwZDI1xGod&G-8VenFsBE*j zS{Sq+2YLokLJZpfdp}!<^>r{m%elhe&k~WRnSOQ&MA^@ttfp26^fP)Y4lLnk<#g8Q z=V$-ZQF}7h*THP``v5kIMV@Bbs3k<%MkV`fZ8ZHN!$vFVT-R(Pv0Y|7QX|*dywAfs zs&e0f7U(tDcc_B7tHzfmV}pn`yQ)2dXlGsQQhHnm)ri3jym9XxjS@U4p&pwN7{Re;g9p87sgFVi($fM%>LORu{xCg$Q#};~ zF!J|`c0(3?XI=gznK4Qf7gB|VUH+BgcWFmWu!@OgR{b``xKb^*o}qUSQE9upI8@4G z(watX7S-u0+WbCMAPiew#ySc^kwc7Zv~NXk5UjYx6HYB9{WEHk7%0(NdQ!acXc$q{zQ~GW@zi&AK={MW77#7Qy_YVHo)i0+=p$qKn*lx41uN+JN8kIrTldg?p6Nj` z=+pbSj<%@fbWX*g5fku7MT&jC$9^{3!=XEfs2rZl7oH6(qLc8n8GJ-LIvv>?v0XzW z25KKxE7d~vE>Cy03yJqx(u-SVF$+Ca?b%1VLZ}A#Lwdc^O*@apVf*ES+qd4*m_s|K z_Y3XSVly=t1pU;5_btsk&&P$!(H3-Zg6J1K8jV6q;={1!c*y)BX6q@aLusdT1%wv@ zc4mAji5Vc-#+;q+Vnn&(j8WRyFlF19K~E{ zyuqY4WZ67dLbKGMPrvBaX1vO@oT@~_1vVTF|5-*;8vf~fZ_^bm z@(DxPDz5D!QCl%*qOp~5mO9wA5QxPb0-)MigS2+^7IaJ{RM!Z{L1aUQPBIW1r3n=M zV20JwGkbq2_wX>WuiLnaxsK6iUv5G_~h-zuIkXmP@ ztkb=%suBZ^7q4bicP?tAaB5ISCzL`{2J!0%_}(?rGz6$SnToZ4R3Iuu4Ls6crw)zIUl|Nabr!%GZ@BH z4AOG&Z>o%-whVFBN8V!|t|AjaE$!qG5dI2aC!TylqpLl4>>#BW+DkjG0tsFKrwFO# zGaI!gyY*PDkbj}G=%8n#0Ol^OLzk9zx`*_atRflx$@~otDrZ#;wF0mZAPiBzd*GE0{{D|n&^yc11cTCysNl>5KdG>|G+AU@D<#07=$NMl!?Eyo)6q{Z^3VcSH|#=MqtP%bYhCgz_l4*r7=Dd3lQ7H* zVV?-(mRzHUN^rz=sie|JJSei*VCPbP)!DKPnsR0NC2NIV96W&%L*~$5=v*a@h`8XY z;zy*1MjGJ08VXu88BXVAANj@r@iH0GQPYk2jME+xA3L_9$JOYXyJpu%J_1> ztfg?{66wv&7+VO_|hLY2f@adHxb&_@g)j*e8!h^tH`kS19tn2FXA-We|))Y8@0IFvli%aP$Izia%xd<*;xN57)s})za$FY_?YTx zjNzzq8-(kx8wG1*El)8D$|=`xWR~p<2M!hm@8kH$8U?M9$0rKf(>g9l6!ep3I_)TU zsQV4YxbUwSTCSefiB@KE?@tSqPG37PqeDwz`>$mAJ*>HD0mQge4^k{v4*jag59z+Pdf^nl>fgJ1-qW` ziGuxM)Wd#J@b`zP@2Wi)Z9o)kp+tZvz^W|<=QefN0jR~g3rLTi&@=LMQY4=2Y21!Q z910MR_t1a8pbSi$IypW3JWB9q(Zs0`o~qz4o?0GC`8&*Jd8~yW0I4!K0iK-FU)-f< zS>otS4lQWLCug^brUd%r?0T_O4fM&`ya!=B{keN(G4rXn{tivGCs7oDckEyNe)7kU z{&}xMd{O6!i@vDS)XKH%hb!sJOZc1)+0ggVpVbdjIsT9SeEop_=#TLPuJNQ8N{|oX z`PZnP`hSOT52)o&qhe)-V#Fg@baqN-hx*5q{%8~x>{X#^Pc|vZtco8U3D59r$(?Yy zKrM+j)N@PlNR?`dqNuO%^Vuc70ZYC{E%^|q()h}&EAmPG#a6g0EH=z}I6tn$dHDM} z;j7;l94<~gPTyXY`5v>+cRcSMvH?BqVR}2&r5p-}^_6C`%6ALlYj`_fn3X(9Bp;@v zd<2S~9>H^B;=xA;)xm7xUh9QvDoI7=pT%#HKgCzwB-v?rU=Lq+6)zl%2fXGIxdczW zQJ~hVvU?E~&wAu_P?WD)fPzmm=hNqah5ipf5ziPRm+x~}_lR21CpF~LR^~I~6}QxD z?n|i+D31mPcvRql;d$Kkmhr<=y8HBI)uQKso>O6mtO7P|0=ARZQCGocXl2z@nzs%t)-?{&ZVbUsQ{R2YL= zSDLWo-kj%qfA8xx z55^OEFq1z{hi^BUlvt*X%W?a}eW%{Cj)N&HF$wrQ&`6IX(c?d8<3zami*$aAOpKz3sNTp zt34#;TzS|%Wv4i=g0f!V9(Cf86eY3=B1c<@XH*Wm+v;-v{u9mVa3$Yu{O>@f+RucV zGBkzuW%SYdZDOw28z-Jo2|T}c6t~DYa6_q1`d6IhePNL!ou<*M!q*yqTw_>+qFSJF*yX{T`yQPbt8Vc0ho zlREYdlJd32pTYI9MmLBAutq-Q0$3wU)V11k5a?%(>xg-J*4PG*kk&Y|I=D5`;LCo# z5lc6!rJaV;8r|0#b4eXrgQR?|Q3|e)HQGTWfHl$~7r+`bMP2a@0?^MIqlkHW)+mQt zNoyRsJGeD=!t}Vm9)kyWx=iC2xN^;v@XWeA++T7^^NOD9b1E>e62AbTpw$EjRju- zYm9|l0BejEb;bLCKtF5rBIfB?;|{o$v_{ok!L6|jk?rRjt!UL++NlFA_kFD~iqx?+ zNXpk5so?rp<1iL!0jx0$asjL{P}CJ~=K%ezaV{}W&l=0%R?-?b ze)xEaxHX|AbUm`y1Gz3xrF_#{D)c3T` zr$20i$UFTjX;5F`tc$=u;=e&vhmvax{z2l>%LDq_jDHJX+f*RB;UvEHI?C|zwTFsz zUppw;roKQLu&l36h_X5~tE@HFvIZDsWt_aMRkEyQ?&h>>sUr|AM#-{v=QXEY>#b$2 zFv_Z=CI+|R8$XJ6^=npHGp%KvYm_zqT*WPbn?s} zEl>-Nz{bZqLm8htOKDL3TH5Kd3|iTUdtV8-XS_w+{iwL~3E7>r$at*P}i{mwf@ClYx1dR{RYDR7AWx7+WJ(qJ`hmrHU3(k zx%m_6XXAmBJtt+6Nk#9^8-jpD`G+&;a*X5>;epfdaGPLAc)ePB{Ec;+HWFKJJ=b9nA zjb&?_Axld`s&7LxWIZe!ih09i+kkcmfeh*G+6>t)EIY6nvIAIlf|T{SDd2nWL?J?Z zZcaP{%mr=*v?64Kv1CFk2K zA^pu$(#c*4>2IErw)RR$fAf@t`zY~Q?~wlBPIefl1eoVo%93oP0(P zF6bgYnX6Blxi_8j2hP0lq?rfNL2%&Ax1Ka}9PRW3&OGy^nHSQ*THwsXPMW#M=Wxi! zV4Y8zxdbOLHYIYly=|M!ubVUb)M=kBhaUXY3-rme#g_AkE$3ca&h56G zWwspb^{Tq*_YK0o|BET@o5=1zVk;KMCVM0HphBm5g=h#}TuDi@92bso%uAn_leai2 zCoe5MFDWlQD?KGYUGVeWX+wu5C8fA?=4GZP%>sFN(%5YGl-!X-&dhcvxfkcAJA#R2 z<)oxV3juQ}eH^Jd+4*kAjSDl~8IGi}Q*s?69J6wAvW7WKdL?Owrd?i;pLcm?c4}5Z zTKeUwmtJ~#?4W+J{bDblmFdpE+*G@M83CJ=k~*K7rA>CHzoSL)K%y^P9$|!Eee@8JX@mj73NA0M zpnh+yhj9LE$8d)`BQyW9k@=ZR(xdxGJtElB7v<*3Zb-??OIbWTX-Y2YF>xNM3)>W= zi|Y2ak;utS&qJW)-8dtf6bo6s?jm|o?O~3r97I<^c7EoZ?DRBh2^D}g#SL@hrO!^! zOV3VCmrd+F3{l96K=I2s!#3ze?X?Bzsi+Qyp$Q1>l&q|r)TET$-1O`;?Lyi9^m)1N z#cTl4Z!!lrdlcnB%Z*yu%gjniog3}jSRw4rK*?zsv4k=-LQq9r$W+5kLL+_KZ{qZ( zz7E>Y`R=SFS$FjCZ=^qC2m3Y%J$>>H)wKV)9}eh$TJ>hL>o9S$d$8>N*w`e@D(>{8 z%z3$4V<%2dibG^C$eEj-H+Hgnkh>r^D}C&^8z#mMn4F%SpOZH+-Mug;Z|>Of^9J;H zItS&`gyftz&zYFDz!{t56cG7{~Gm=9sHlQkH7w3*FOIGe_i{;1u@UB zVShjUCiDD9^egj(bZs%L4$lxQ!7aWV?R-4I2wVxw0)7W9174ix^;Q5!0}len0gnTh0y}olv`2sgfzJS^0QUmj zz$3slz`^;j6YwVBLEr%(eJQE0+w1L2AE^e$0ha)$0e1lDE7SCa?G3<3fP0A!JPh2l z!0QdeH?S5h^m=;&Yk)4`Ry?JV0bIEl?FJqM(tmSmCw8~#n^|SpxIPB_8Q7+irqyFB zzb~*I4mHLD`vS9o_X6(#ZU=4#egvd%zb#*edIMV)dc6*OFKr(%9yo0|$^|Y076DJJ zfW3e_Rw5s8A|9)00_Flc8SG&c0*?bX01vH3y@A>q_y@2j zwq_joEN3<_9=HRT415IpJu89x@Qz3Yu;n_G2W$j30XyE0e(k1daeqcVfg{($pMbL- zKsmt8z$)M-yaC_=?tch=c)q56j<-ePfo<>(O)@YSxDptL?*Wtpmji2n8-O0*0bm5a z+L(wpyrO}t=}j+S96qLz0bCC(0yY54f$j0mTn+G2pa=LOunoS5`wp-#eHr(!@FU=l z<*+Mo=3}rcFm1Efy93zqZ(i>q;8frV;4+}Y0s8~vfqN^^pTPZ3d%f#`{hq-SLcoD| zI`uHn4Gg;w{;?hX04#g~;{@<9a4GOe73vARWEbiQjMwpg)M0+oW zf4u?w0=K^j`vPm;LOp?R)}b6=&$m$ya3%0K@Ihe5XiaPV4#sa_3~)M-zQ?r`_$+We zu>ZU817JMx5b&?S6TsGoF#h8nYyof#@FQRraN>JtA8_C?06ac02l}S5jY(f zeHi5ervf(uR|0E*TY(@O5Af@MoY0 z*yl^+zXIzUU^Flr=mM4jGk{M6i-2zc%YjY68eo@3!MZgb%<-o9SkRR9`=mCxbMhwFwl6lzy?8FtBlo|w%vjq*;%-_RLe?>R&m)h_C` z(5u?E{67?cB=MKxF9v+lsq>Qz{(6uHfGe2~kuD@F-*6l&` z4`)86Nu&HUL;rN}k08HY|1Jgp3-Imgx1RIc@ppj#De~L-2URO%Ny2#H*{%M(_8Lv= zs{EVkM1Qx!kI#c0!al>~rTW0NqD6}~A-WxUw!rw0a_szI4EX!N??MGC9f^h=(!j3* zAJePB&yaivNSpEZ3iuO%Ve?G&2z3b|lBvaC6J)5ZVH3^9o5Af|`t_=Kk z;7>H?4;`zQUjhDb@Y|XBk}bxRTJSFcpKNK=U)qskrV;$>!N*e2;HMh(iwdVRxWIkw zK$aNr6TrX2oZq>kMd)%v#}vp^LMF*96Dk9f>fi?dd+;&c7{g9jymvjzz-BVl!fYX0y489(~1bnZ$}$tbZd$64}2_Z4E{WW zPhT-h2H$S{nhrkcw;lh$p9X%US-*5uQNQ)zyTI>d<|iBF?*O0bcdeNpDhF_C-y!gq zfKT(4-o6~eMkm0(6Z{l2pX_X!LmV*90mvkqWkPQhN~nx@@Y|%=&q2xHM}TiK8E#%klLyr18>>87tX}mv%vfhM@-8j_- z6LT&24d%Lp9@g917ySEYdA+au@Lv{u2WaHi<5PM3sm83J>S~%(a-m}pWbDc)1Alay zeHrA}$HAvLD{M~SGU)r6j&%Dnj)Q*${6OuXKJ9oG_9JF{z4P$fXoDQEi9ZnhBjA7N z!#||kX$tt8=L8<_DZd;1?cifu!_fbG*_Xs$1AZm=nPz^doLGtf4EUiLf#+2R_~h3u z!M_;4!>)-o%9tg~AipBNZVj0YBy+JzhWzSYL(T=c<&dMN1H;;ys?KH-a^fkZ;+lY$?9q4?aM-V=p zJ9GyhrZDPYD!*e}#0L2BX8z5x&q@D4@Gk*BQ2iX>FNN>*1pgBJ4s&AmQhk|j=vc%$ zIw2l(ev2p(2vo*8@EvaZxwR7f-r)Cvte)Sr_O1i}a_|qE`KEPT6Zpr$zsHAvr{2$< zvB1hGz}}OYFQ+{*H^(tQQ2CT+8u)q0|A{$2_4B*Z1{g`Sjp%@ZIA6Gk#)JzI-O5ha z-r1rw?2hmiEnEDK3_|uOhrYfG1NRAy3*^`1!T$`u!)QZP>7p{52MaxuX@8?F32@PPT1=`lUx9MxgqPhg=J}T zTlIlOmfE`ry9xEnyxwrL|5MpN8D;N zcFi3vR)mF$9Sf4#44K1_sWHn?{ddaxQ#rMeDO&0Ejx)=II)wo78^PZSzU}yr#d-z! zmzwj>HuT4UPiJk#W`5{OU4H`jy;ga>*jh5$vB=1u3;t;EA2stsH|Y7xz^?({#}1)# zQ;6zc0e+j?0>_bPKlnqyr~c9HXu7{^1b-Cxc4K$c?=)=~_-oAh$;P)EZ5Rj{dVN2T z4ywZx@Hc@^Z$9XCXz`R7+Z`ae!5?0P^_`hd>!9hzI%pkamKS@ysgT!ogw7O|ptjY+ z-}iyvvIYG45!}tISevMio!^8)n(9O6xEt>9dY|;s^|)?xI^T^c^?FB}`M1dSIzXdy z>Pg^Zb)$uiGnK{bNh*WRgr`C#9>4Xv@SI8YrL*k?;EVdUHtDd`mt=Q9Hld7VzlNs< zX+Rcc0J@UF7v=U3u8YpjhdyNAhR*PX8^9O3emvi3XMlbf1KEL(uJq4fvgd z@IByn03WR|^z&Y@1Eh#^@gJ83f4-Sdac|ml=?j_ZkXdS$30puW~NANK;80BAU^uaOk!@yr?=7;79 z0S9PpI-`Byd(C{Z!MBEv7|6u^HSj!3{hR>)Ebxb#brcx+bHQH<{s=SQG(VJqe;@e$ z&3x0IQw8{&!7niLLvuv|RDLb^q2*rhBp<%qbSHiz_yfVe)`xHG8AY9kSOY)Mx|Z_C zfS(DzogXKFp8>wpM}NFtzg+N3!4KreG;UPFPm92BM{DBckWypc*wPkvgsli~p&4_; z4(Ph+F|QXZ4?}K-Ve3QSXMrDM=Fc_wC%|6{zTI5k4aNTve7m*8aPYT+Z@1>14*ntV zCz#9UJ#A|1M)+gv$GNRrP#K%Hl58zxk15&vgUg

?=>O-rIu9(lb64n^`t5xa<_j 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 Q``_|CzH-I5!T4JFf2(xW%K!iX literal 85008 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 diff --git a/sensor_network.cpp b/sensor_network.cpp index 038a7ca..ddf33a4 100644 --- a/sensor_network.cpp +++ b/sensor_network.cpp @@ -3,136 +3,51 @@ #include #include -/** - * Startet alle Threads des Netzwerks - * @param num_sensors Anzahl der Sensor-Threads - * @param num_analysers Anzahl der Analyse-Threads - */ template -void SensorNetwork::start(size_t num_sensors, size_t num_analysers) { +void SensorNetwork::start(size_t sensors, size_t analysers) { running = true; - - // Starte Sensor-Threads - for(size_t i = 0; i < num_sensors; ++i) { - sensors.emplace_back([this, i] { - sensor_thread(i); + + // Sensor threads + for (size_t i = 0; i < sensors; ++i) { + threads.emplace_back([this] { + std::mt19937 gen(std::random_device{}()); + std::uniform_int_distribution<> dist(0, 100); + while (running) { + std::this_thread::sleep_for(std::chrono::milliseconds(100 + gen() % 400)); + buffer.push(dist(gen)); + } }); } - // Starte Analyse-Threads - for(size_t i = 0; i < num_analysers; ++i) { - analysers.emplace_back([this, i] { - analyser_thread(i); + // Analyser threads + for (size_t i = 0; i < analysers; ++i) { + threads.emplace_back([this] { + while (running) { + int data = buffer.pop(); + int model_val = model.read(); + std::cout << "Data: " << data << " Model: " << model_val << "\n"; + } }); } - // Starte Controller-Thread - controller = std::thread([this] { - controller_thread(); + // Controller thread + threads.emplace_back([this] { + std::mt19937 gen(std::random_device{}()); + while (running) { + std::this_thread::sleep_for(std::chrono::milliseconds(500 + gen() % 1500)); + model.write(gen() % 100); + } }); } -/** - * Stoppt alle Threads und wartet auf Beendigung - */ template void SensorNetwork::stop() { running = false; - - // Warte auf Thread-Ende - for(auto& t : sensors) { + for (auto& t : threads) { if (t.joinable()) t.join(); } - for(auto& t : analysers) { - if (t.joinable()) t.join(); - } - if (controller.joinable()) { - controller.join(); - } } -/** - * Thread-Funktion für Sensoren (Producer) - * @param id Eindeutige ID des Sensors - * - * Funktionsweise: - * 1. Generiert zufällige Messwerte - * 2. Wartet zufällige Zeit (Messintervall) - * 3. Schreibt Daten in Ringpuffer - */ -template -void SensorNetwork::sensor_thread(int id) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> data_gen(0, 100); // Messwerte 0-100 - std::uniform_int_distribution<> sleep_gen(100, 500); // Intervall 100-500ms - - while(running) { - // Simuliere Messintervall - std::this_thread::sleep_for( - std::chrono::milliseconds(sleep_gen(gen)) - ); - - // Generiere und schreibe Messwert - int value = data_gen(gen); - buffer.push(value); - - std::cout << "Sensor " << id << " produced: " << value << "\n"; - } -} - -/** - * Thread-Funktion für Analyse-Module (Consumer) - * @param id Eindeutige ID des Moduls - * - * Funktionsweise: - * 1. Liest Daten aus Ringpuffer (blockierend) - * 2. Liest aktuelles Analysemodell - * 3. Verarbeitet Daten (hier nur Ausgabe) - */ -template -void SensorNetwork::analyser_thread(int id) { - while(running) { - // Blockierendes Lesen aus Puffer - int data = buffer.pop(); - - // Lesender Zugriff auf Analysemodell - int model_value = model.read(); - - std::cout << "Analyser " << id << " processed: " << data - << " | Model: " << model_value << "\n"; - } -} - -/** - * Thread-Funktion für System-Controller (Writer) - * - * Funktionsweise: - * 1. Wartet zufällige Zeit zwischen Updates - * 2. Schreibt neuen Wert ins Analysemodell - */ -template -void SensorNetwork::controller_thread() { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> update_gen(0, 100); // Modellwerte - std::uniform_int_distribution<> sleep_gen(500, 2000); // Update-Intervall - - while(running) { - // Warte bis zum nächsten Update - std::this_thread::sleep_for( - std::chrono::milliseconds(sleep_gen(gen)) - ); - - // Aktualisiere Analysemodell - int new_value = update_gen(gen); - model.write(new_value); - - std::cout << "Controller updated model to: " << new_value << "\n"; - } -} - -// Explizite Instanziierung für gängige Puffergrößen template class SensorNetwork<8>; template class SensorNetwork<16>; -template class SensorNetwork<32>; \ No newline at end of file +template class SensorNetwork<32>; diff --git a/sensor_network.h b/sensor_network.h index 1480dc3..148f2fa 100644 --- a/sensor_network.h +++ b/sensor_network.h @@ -5,37 +5,15 @@ #include "ring_buffer.h" #include "analysis_model.h" -/** - * Hauptklasse des Sensornetzwerks - * @tparam N Größe des Ringpuffers - * - * Verwaltet alle Komponenten: - * - Ringpuffer für Sensordaten - * - Analysemodell - * - Threads für Sensoren, Analyse und Controller - */ template class SensorNetwork { - RingBuffer buffer; // Gemeinsamer Datenpuffer - AnalysisModel model; // Geteiltes Analysemodell - std::atomic running{false}; // Steuerflag für Threads - - // Thread-Container - std::vector sensors; - std::vector analysers; - std::thread controller; + RingBuffer buffer; + AnalysisModel model; + std::atomic running = false; + std::vector threads; public: - ~SensorNetwork() { - if (running) stop(); - } - - void start(size_t num_sensors, size_t num_analysers); + ~SensorNetwork() { if (running) stop(); } + void start(size_t sensors, size_t analysers); void stop(); - -private: - // Thread-Funktionen - void sensor_thread(int id); - void analyser_thread(int id); - void controller_thread(); -}; \ No newline at end of file +}; From b12ae5b0cb90dc12fdbca85f4e5de900521e92a0 Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Tue, 3 Jun 2025 01:40:44 +0200 Subject: [PATCH 2/4] added comments --- analysis_model.h | 18 ++++++++++++++-- main.cpp | 17 +++++++++++++-- ring_buffer.h | 54 +++++++++++++++++++++++++++++++++++----------- sensor_network.cpp | 40 ++++++++++++++++++++++++++++------ sensor_network.h | 18 ++++++++++++---- 5 files changed, 120 insertions(+), 27 deletions(-) diff --git a/analysis_model.h b/analysis_model.h index e17e11b..e775eb5 100644 --- a/analysis_model.h +++ b/analysis_model.h @@ -1,16 +1,30 @@ #pragma once #include +/** + * Thread-sicheres Analysemodell + * Vereinfachte Implementierung mit: + * - Einfachem Mutex-Schutz (kein Reader-Writer-Lock) + * - Für seltene Schreibzugriffe geeignet + */ class AnalysisModel { - int value = 0; - std::mutex mtx; + int value = 0; // Der gespeicherte Wert + std::mutex mtx; // Schützt Lese/Schreibzugriffe public: + /** + * Liest den aktuellen Wert + * @return Der gespeicherte Wert + */ int read() { std::lock_guard lock(mtx); return value; } + /** + * Schreibt einen neuen Wert + * @param new_val Der neue Wert + */ void write(int new_val) { std::lock_guard lock(mtx); value = new_val; diff --git a/main.cpp b/main.cpp index d13d9c2..0b81389 100644 --- a/main.cpp +++ b/main.cpp @@ -1,13 +1,26 @@ #include "sensor_network.h" #include +/** + * Hauptprogramm + * Startet die Simulation mit festen Parametern + * (Könnte leicht für interaktive Eingabe erweitert werden) + */ int main() { + // Netzwerk mit Puffergröße 8 erstellen SensorNetwork<8> network; - std::cout << "Starting simulation...\n"; - network.start(2, 2); // 2 sensors, 2 analysers + std::cout << "Starting simulation...\n"; + + // 2 Sensoren und 2 Analyse-Module starten + network.start(2, 2); + + // 30 Sekunden laufen lassen std::this_thread::sleep_for(std::chrono::seconds(30)); + + // Netzwerk stoppen network.stop(); + std::cout << "Simulation finished\n"; return 0; } diff --git a/ring_buffer.h b/ring_buffer.h index 4e7a0ff..bb7b34c 100644 --- a/ring_buffer.h +++ b/ring_buffer.h @@ -3,31 +3,61 @@ #include #include +/** + * Thread-sicherer Ringpuffer mit fester Größe N + * Implementiert das Producer-Consumer-Pattern mit: + * - Mutex für exklusiven Zugriff + * - Condition Variable für blockierendes Lesen + * - Überschreibt älteste Daten bei vollem Puffer + */ template class RingBuffer { - std::array data; - size_t read = 0; - size_t write = 0; - bool full = false; - std::mutex mtx; - std::condition_variable cv; + std::array data; // Speicher für die Elemente + size_t read = 0; // Lese-Position + size_t write = 0; // Schreib-Position + bool full = false; // Flag für vollen Puffer + + std::mutex mtx; // Schützt alle Zugriffe + std::condition_variable cv; // Synchronisiert Leser public: + /** + * Schreibt einen Wert in den Puffer + * @param value Der zu schreibende Wert + * + * Funktionsablauf: + * 1. Sperrt den Puffer mit Mutex + * 2. Schreibt Wert an aktueller Position + * 3. Überschreibt ältesten Wert wenn voll + * 4. Aktualisiert Schreib-Position + * 5. Benachrichtigt wartende Leser + */ void push(int value) { std::lock_guard lock(mtx); data[write] = value; - write = (write + 1) % N; - if (full) read = (read + 1) % N; - full = (write == read); - cv.notify_one(); + write = (write + 1) % N; // Ringverhalten + if (full) read = (read + 1) % N; // Überschreiben + full = (write == read); // Update Voll-Flag + cv.notify_one(); // Wecke einen Leser } + /** + * Liest einen Wert aus dem Puffer (blockierend) + * @return Der gelesene Wert + * + * Funktionsablauf: + * 1. Sperrt den Puffer + * 2. Wartet bis Daten verfügbar + * 3. Liest Wert und aktualisiert Position + * 4. Gibt Wert zurück + */ int pop() { std::unique_lock lock(mtx); + // Warte bis Daten da sind (verhindert Busy Waiting) cv.wait(lock, [this]{ return full || write != read; }); int val = data[read]; - read = (read + 1) % N; - full = false; + read = (read + 1) % N; // Ringverhalten + full = false; // Nicht mehr voll return val; } }; diff --git a/sensor_network.cpp b/sensor_network.cpp index ddf33a4..bd8c6fd 100644 --- a/sensor_network.cpp +++ b/sensor_network.cpp @@ -3,51 +3,77 @@ #include #include +/** + * Startet das Sensornetzwerk + * @param sensors Anzahl der Sensor-Threads + * @param analysers Anzahl der Analyse-Threads + */ template void SensorNetwork::start(size_t sensors, size_t analysers) { running = true; - // Sensor threads + // Sensor-Threads erstellen for (size_t i = 0; i < sensors; ++i) { threads.emplace_back([this] { std::mt19937 gen(std::random_device{}()); std::uniform_int_distribution<> dist(0, 100); + while (running) { - std::this_thread::sleep_for(std::chrono::milliseconds(100 + gen() % 400)); + // Zufälliges Intervall (100-500ms) + std::this_thread::sleep_for( + std::chrono::milliseconds(100 + gen() % 400)); + + // Messwert generieren und speichern buffer.push(dist(gen)); } }); } - // Analyser threads + // Analyse-Threads erstellen for (size_t i = 0; i < analysers; ++i) { threads.emplace_back([this] { while (running) { + // Daten aus Puffer lesen int data = buffer.pop(); + + // Analysemodell lesen int model_val = model.read(); - std::cout << "Data: " << data << " Model: " << model_val << "\n"; + + // Ausgabe (könnte auch analysieren) + std::cout << "Data: " << data + << " Model: " << model_val << "\n"; } }); } - // Controller thread + // Controller-Thread erstellen threads.emplace_back([this] { std::mt19937 gen(std::random_device{}()); while (running) { - std::this_thread::sleep_for(std::chrono::milliseconds(500 + gen() % 1500)); + // Zufälliges Update-Intervall (500-2000ms) + std::this_thread::sleep_for( + std::chrono::milliseconds(500 + gen() % 1500)); + + // Analysemodell aktualisieren model.write(gen() % 100); } }); } +/** + * Stoppt das Sensornetzwerk und wartet auf Threads + */ template void SensorNetwork::stop() { - running = false; + running = false; // Signal zum Stoppen + + // Auf alle Threads warten for (auto& t : threads) { if (t.joinable()) t.join(); } } +// Explizite Instanziierungen für gängige Puffergrößen template class SensorNetwork<8>; template class SensorNetwork<16>; template class SensorNetwork<32>; diff --git a/sensor_network.h b/sensor_network.h index 148f2fa..af314c2 100644 --- a/sensor_network.h +++ b/sensor_network.h @@ -5,15 +5,25 @@ #include "ring_buffer.h" #include "analysis_model.h" +/** + * Hauptklasse für das Sensornetzwerk + * @tparam N Größe des Ringpuffers + * + * Verwaltet alle Komponenten: + * - Ringpuffer für Sensordaten + * - Analysemodell + * - Threads für Sensoren, Analyse und Controller + */ template class SensorNetwork { - RingBuffer buffer; - AnalysisModel model; - std::atomic running = false; - std::vector threads; + RingBuffer buffer; // Gemeinsamer Datenpuffer + AnalysisModel model; // Geteiltes Analysemodell + std::atomic running = false; // Steuerflag für Threads + std::vector threads; // Alle Threads public: ~SensorNetwork() { if (running) stop(); } + void start(size_t sensors, size_t analysers); void stop(); }; From d194d9e18d79a63ae880cf3efc8909bb0189873a Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Tue, 3 Jun 2025 01:49:23 +0200 Subject: [PATCH 3/4] removed comments --- analysis_model.h | 44 +++++------------------------------- main.cpp | 19 ++-------------- ring_buffer.h | 55 ++++++--------------------------------------- sensor_network | Bin 85008 -> 144968 bytes sensor_network.cpp | 54 +++++--------------------------------------- sensor_network.h | 19 ++++------------ 6 files changed, 24 insertions(+), 167 deletions(-) diff --git a/analysis_model.h b/analysis_model.h index 4b4be10..111ddbe 100644 --- a/analysis_model.h +++ b/analysis_model.h @@ -2,50 +2,28 @@ #include #include -/** - * Implementiert das Reader-Writer Problem mit: - * - Mehrere gleichzeitige Leser - * - Exklusiver Zugriff für Schreiber - * - Verhindert Writer-Starvation - */ class AnalysisModel { - int value = 0; // Das geteilte Analysemodell (vereinfacht) - int reader_count = 0; // Zählt aktive Leser + int value = 0; + int reader_count = 0; - // Synchronisationsprimitive - std::mutex model_mutex; // Schützt Schreibzugriffe (exklusiv) - std::mutex count_mutex; // Schützt Leserzähler - std::condition_variable no_writer; // Garantiert Fairness + std::mutex model_mutex; + std::mutex count_mutex; + std::condition_variable no_writer; public: - /** - * Lesender Zugriff - * @return Aktueller Wert des Modells - * - * Funktionsweise: - * 1. Sperrt count_mutex und inkrementiert reader_count - * 2. Erster Leser sperrt model_mutex (blockiert Writer) - * 3. Entsperrt count_mutex während des Lesens - * 4. Liest Wert - * 5. Sperrt count_mutex zum Dekrementieren - * 6. Letzter Leser entsperrt model_mutex und benachrichtigt Writer - */ int read() { std::unique_lock count_lock(count_mutex); reader_count++; - // Erster Leser sperrt für Writer if(reader_count == 1) { model_mutex.lock(); } count_lock.unlock(); - // Kritischer Abschnitt (Lesen, kann parallel erfolgen) int result = value; count_lock.lock(); reader_count--; - // Letzter Leser gibt für Writer frei if(reader_count == 0) { model_mutex.unlock(); no_writer.notify_one(); @@ -54,22 +32,12 @@ public: return result; } - /** - * Schreibender Zugriff - * @param new_value Neuer Wert für das Modell - * - * Funktionsweise: - * 1. Sperrt model_mutex (exklusiver Zugriff) - * 2. Schreibt neuen Wert - * 3. Wartet bis alle Leser fertig sind (Starvation Prevention) - */ void write(int new_value) { std::unique_lock lock(model_mutex); value = new_value; - // Verhindert Writer-Starvation no_writer.wait(lock, [this]() { return reader_count == 0; }); } -}; \ No newline at end of file +}; diff --git a/main.cpp b/main.cpp index b608ad5..9b2ae67 100644 --- a/main.cpp +++ b/main.cpp @@ -4,16 +4,11 @@ #include #include -// Standardkonfiguration constexpr size_t DEFAULT_NUM_SENSORS = 3; constexpr size_t DEFAULT_NUM_ANALYSERS = 2; -constexpr int DEFAULT_RUN_TIME = 30; // Sekunden +constexpr int DEFAULT_RUN_TIME = 30; constexpr size_t DEFAULT_BUFFER_SIZE = 8; -/** - * Führt die Simulation mit gegebenen Parametern aus - * @tparam N Puffergröße - */ template void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { SensorNetwork network; @@ -30,21 +25,13 @@ void run_simulation(size_t num_sensors, size_t num_analysers, int run_time) { std::cout << "\n=== Simulation beendet ===\n"; } -/** - * Liest Benutzereingabe mit Standardwert - * @param prompt Eingabeaufforderung - * @param default_value Standardwert bei leerer Eingabe - * @return Eingegebener oder Standardwert - */ size_t get_input(const std::string& prompt, size_t default_value) { std::cout << prompt << " [" << default_value << "]: "; std::string input; std::getline(std::cin, input); - // Verwende Standardwert bei leerer Eingabe if(input.empty()) return default_value; - // Konvertiere Eingabe try { return std::stoul(input); } catch(...) { @@ -58,7 +45,6 @@ int main() { std::cout << "=== Sensornetzwerk-Simulation ===\n" << "(Leere Eingabe verwendet Standardwerte)\n"; - // Interaktive Konfiguration size_t num_sensors = get_input("Anzahl Sensoren", DEFAULT_NUM_SENSORS); size_t num_analysers = get_input("Anzahl Analysemodule", DEFAULT_NUM_ANALYSERS); int run_time = static_cast( @@ -66,7 +52,6 @@ int main() { ); size_t buffer_size = get_input("Puffergröße", DEFAULT_BUFFER_SIZE); - // Starte Simulation basierend auf Puffergröße switch(buffer_size) { case 8: run_simulation<8>(num_sensors, num_analysers, run_time); @@ -87,4 +72,4 @@ int main() { std::cout << "Simulation erfolgreich abgeschlossen.\n"; return 0; -} \ No newline at end of file +} diff --git a/ring_buffer.h b/ring_buffer.h index ee992c8..fc94a85 100644 --- a/ring_buffer.h +++ b/ring_buffer.h @@ -4,30 +4,19 @@ #include #include -/** - * Thread-sicherer Ringpuffer mit fester Größe - * @tparam N Größe des Puffers (muss > 1 sein) - * - * Implementiert das Producer-Consumer Pattern mit: - * - Mutex für exklusiven Zugriff - * - Condition Variable für blockierendes Pop - * - Überschreibt älteste Daten bei vollem Puffer - */ template class RingBuffer { static_assert(N > 1, "Buffer size must be greater than 1"); private: - std::vector data; // Speicher für Elemente - size_t read_ptr = 0; // Lesezeiger (nächstes zu lesendes Element) - size_t write_ptr = 0; // Schreibzeiger (nächstes freie Position) - bool full = false; // Flag, ob Puffer voll ist + std::vector data; + size_t read_ptr = 0; + size_t write_ptr = 0; + bool full = false; - // Synchronisationsprimitive - std::mutex mtx; // Schützt alle internen Zustände - std::condition_variable not_empty; // Signalisiert, dass Daten verfügbar sind + std::mutex mtx; + std::condition_variable not_empty; - // Hilfsfunktion: Zeiger mit Ringverhalten bewegen size_t advance(size_t ptr) const { return (ptr + 1) % N; } @@ -35,56 +24,28 @@ private: public: RingBuffer() : data(N, 0) {} - /** - * Schreibt Wert in den Puffer - * @param value Der zu schreibende Wert - * - * Funktionsweise: - * 1. Sperrt Mutex für exklusiven Zugriff - * 2. Schreibt Wert an aktueller write_ptr - * 3. Bei vollem Puffer: Bewegt read_ptr (überschreibt ältesten Wert) - * 4. Aktualisiert write_ptr und full-Flag - * 5. Benachrichtigt einen wartenden Consumer - */ void push(int value) { std::unique_lock lock(mtx); - // Schreibe Wert data[write_ptr] = value; - // Überschreibe ältesten Wert bei vollem Puffer if(full) { read_ptr = advance(read_ptr); } - // Zeiger aktualisieren write_ptr = advance(write_ptr); full = (write_ptr == read_ptr); - // Benachrichtige einen wartenden Consumer not_empty.notify_one(); } - /** - * Liest Wert aus dem Puffer (blockierend) - * @return Der gelesene Wert - * - * Funktionsweise: - * 1. Sperrt Mutex - * 2. Wartet mit Condition Variable bis Daten verfügbar - * 3. Liest Wert an read_ptr - * 4. Aktualisiert read_ptr und full-Flag - * 5. Gibt Wert zurück - */ int pop() { std::unique_lock lock(mtx); - // Warte bis Daten verfügbar (verhindert Busy Waiting) not_empty.wait(lock, [this]() { return !is_empty(); }); - // Lese und aktualisiere Zustand int value = data[read_ptr]; read_ptr = advance(read_ptr); full = false; @@ -92,13 +53,11 @@ public: return value; } - // Prüft ob Puffer leer ist bool is_empty() const { return !full && (read_ptr == write_ptr); } - // Prüft ob Puffer voll ist bool is_full() const { return full; } -}; \ No newline at end of file +}; diff --git a/sensor_network b/sensor_network index a918fbc171ebbd4db0f619bcea1b551b07d61c64..e01a28976c8707340941c1d7a4e6fff0397a420d 100755 GIT binary patch literal 144968 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 literal 85008 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 diff --git a/sensor_network.cpp b/sensor_network.cpp index 038a7ca..65b5247 100644 --- a/sensor_network.cpp +++ b/sensor_network.cpp @@ -3,43 +3,31 @@ #include #include -/** - * Startet alle Threads des Netzwerks - * @param num_sensors Anzahl der Sensor-Threads - * @param num_analysers Anzahl der Analyse-Threads - */ template void SensorNetwork::start(size_t num_sensors, size_t num_analysers) { running = true; - // Starte Sensor-Threads for(size_t i = 0; i < num_sensors; ++i) { sensors.emplace_back([this, i] { sensor_thread(i); }); } - // Starte Analyse-Threads for(size_t i = 0; i < num_analysers; ++i) { analysers.emplace_back([this, i] { analyser_thread(i); }); } - // Starte Controller-Thread controller = std::thread([this] { controller_thread(); }); } -/** - * Stoppt alle Threads und wartet auf Beendigung - */ template void SensorNetwork::stop() { running = false; - // Warte auf Thread-Ende for(auto& t : sensors) { if (t.joinable()) t.join(); } @@ -51,29 +39,18 @@ void SensorNetwork::stop() { } } -/** - * Thread-Funktion für Sensoren (Producer) - * @param id Eindeutige ID des Sensors - * - * Funktionsweise: - * 1. Generiert zufällige Messwerte - * 2. Wartet zufällige Zeit (Messintervall) - * 3. Schreibt Daten in Ringpuffer - */ template void SensorNetwork::sensor_thread(int id) { std::random_device rd; std::mt19937 gen(rd()); - std::uniform_int_distribution<> data_gen(0, 100); // Messwerte 0-100 - std::uniform_int_distribution<> sleep_gen(100, 500); // Intervall 100-500ms + std::uniform_int_distribution<> data_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(100, 500); while(running) { - // Simuliere Messintervall std::this_thread::sleep_for( std::chrono::milliseconds(sleep_gen(gen)) ); - // Generiere und schreibe Messwert int value = data_gen(gen); buffer.push(value); @@ -81,22 +58,11 @@ void SensorNetwork::sensor_thread(int id) { } } -/** - * Thread-Funktion für Analyse-Module (Consumer) - * @param id Eindeutige ID des Moduls - * - * Funktionsweise: - * 1. Liest Daten aus Ringpuffer (blockierend) - * 2. Liest aktuelles Analysemodell - * 3. Verarbeitet Daten (hier nur Ausgabe) - */ template void SensorNetwork::analyser_thread(int id) { while(running) { - // Blockierendes Lesen aus Puffer int data = buffer.pop(); - // Lesender Zugriff auf Analysemodell int model_value = model.read(); std::cout << "Analyser " << id << " processed: " << data @@ -104,27 +70,18 @@ void SensorNetwork::analyser_thread(int id) { } } -/** - * Thread-Funktion für System-Controller (Writer) - * - * Funktionsweise: - * 1. Wartet zufällige Zeit zwischen Updates - * 2. Schreibt neuen Wert ins Analysemodell - */ template void SensorNetwork::controller_thread() { std::random_device rd; std::mt19937 gen(rd()); - std::uniform_int_distribution<> update_gen(0, 100); // Modellwerte - std::uniform_int_distribution<> sleep_gen(500, 2000); // Update-Intervall + std::uniform_int_distribution<> update_gen(0, 100); + std::uniform_int_distribution<> sleep_gen(500, 2000); while(running) { - // Warte bis zum nächsten Update std::this_thread::sleep_for( std::chrono::milliseconds(sleep_gen(gen)) ); - // Aktualisiere Analysemodell int new_value = update_gen(gen); model.write(new_value); @@ -132,7 +89,6 @@ void SensorNetwork::controller_thread() { } } -// Explizite Instanziierung für gängige Puffergrößen template class SensorNetwork<8>; template class SensorNetwork<16>; -template class SensorNetwork<32>; \ No newline at end of file +template class SensorNetwork<32>; diff --git a/sensor_network.h b/sensor_network.h index 1480dc3..468af5f 100644 --- a/sensor_network.h +++ b/sensor_network.h @@ -5,22 +5,12 @@ #include "ring_buffer.h" #include "analysis_model.h" -/** - * Hauptklasse des Sensornetzwerks - * @tparam N Größe des Ringpuffers - * - * Verwaltet alle Komponenten: - * - Ringpuffer für Sensordaten - * - Analysemodell - * - Threads für Sensoren, Analyse und Controller - */ template class SensorNetwork { - RingBuffer buffer; // Gemeinsamer Datenpuffer - AnalysisModel model; // Geteiltes Analysemodell - std::atomic running{false}; // Steuerflag für Threads + RingBuffer buffer; + AnalysisModel model; + std::atomic running{false}; - // Thread-Container std::vector sensors; std::vector analysers; std::thread controller; @@ -34,8 +24,7 @@ public: void stop(); private: - // Thread-Funktionen void sensor_thread(int id); void analyser_thread(int id); void controller_thread(); -}; \ No newline at end of file +}; From cbcaff968589d05f065f26793925c6893fde43fc Mon Sep 17 00:00:00 2001 From: portnoytmy Date: Tue, 3 Jun 2025 06:55:25 +0000 Subject: [PATCH 4/4] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a5689b8..4653416 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -/* ### Erklärung der Praktikumsaufgabe (Synchronisation) +### Erklärung der Praktikumsaufgabe (Synchronisation) #### **Kernziel der Aufgabe** Sie sollen ein **multithreaded Sensornetzwerk** simulieren, das drei Komponenten umfasst: @@ -151,5 +151,4 @@ Starten Sie das System mit verschiedenen Parametern und beobachten Sie: Mit dieser Struktur erfüllen Sie alle Lernziele: ✅ Reader-Writer-Problem ✅ Producer-Consumer-Pattern -✅ Vermeidung von Race Conditions & Deadlocks! -*/ \ No newline at end of file +✅ Vermeidung von Race Conditions & Deadlocks! \ No newline at end of file