Eigenes std::cout



  • Die Frage ist, warum es nicht geht... sry - hatte ich im Eifer des gefechts vergessen, mit hin zu schreiben... Er will einfach das rechts nicht umwandeln... sagt mir dann ständig, dass er const char [4] oder wie viel zeichen auch immer, nicht umwandeln kann...

    pumuckl: ok - der operator gibt jz ne const ref. auf den stream zurück...
    warum muss die klasse den von ostream erben? dafür hab ich ja das "normale" std::cout... oder seh ich da was falsch?

    "Die vermutlich sinnigere Alternative ist, dass die einzelnen Threads keine eigenständige Ausgabe machen dürfen" Naja... Da hab ich auch schon lang drüber nachgedacht - aber ist in meinem Fall nicht so einfach machbar... Hab ich wo am Anfang auch nicht ordentlich drüber nachgedacht - und das jz noch zu ändenr wäre der Horror - und hab ich eigtl auch nicht vor ^^



  • Dein Versuch der Ausgabe funktioniert deshalb nicht, weil du nur einen operator<< (ostream&) definiert hast - Sprich du kannst in my_out nur ostreams packen, keine const char* s wie bei dir vorgesehen. Du müsstest, um allgemeine Ausgabe machen zu können, deine KLasse von ostream abeliten und entsprechend mit dem Streambuf usw. rumwerkeln - viel Spaß dabei ^^



  • hmm... verdammt ^^ hatte mir das eigtl genau so einfach vorgestellt ^^ naja - ma gucken, ob ich das hinbekomm (würd ja ma denken, dass es jz geht aber kanns gerad ne ausprobieren, weil noch millionen andere fehler im projekt sind, weil ich was ändern musste -.-)... danke erst mal :>

    bb



  • pumuckl schrieb:

    Dein Versuch der Ausgabe funktioniert deshalb nicht, weil du nur einen operator<< (ostream&) definiert hast - Sprich du kannst in my_out nur ostreams packen, keine const char* s wie bei dir vorgesehen. Du müsstest, um allgemeine Ausgabe machen zu können, deine KLasse von ostream abeliten und entsprechend mit dem Streambuf usw. rumwerkeln - viel Spaß dabei ^^

    Dadurch kommt aber keine echte Threadsicherheit zustande, da die Standard-op<<s nicht threadsicher sind (die können ihre Ausgabe ja in mehrere Teile zerlegt tätigen).
    Man muss sich also wirklich hier die Mühe machen und alles threadsicher implementieren. Bevor du das machst könntest du aber auch einfach mal schauen ob du wirklich Compiler-unabhängig sein musst und wenn nicht schauen ob dein Compiler vielleicht eine Option bietet mit der die Standardbibliothek thread-sicher wird.
    Beim VC geht das zum Beispiel.



  • 'Beim VC geht das zum Bsp.'
    Oo
    verdammt - hätte man davor auch ma drauf kommen können - aber naja... zu spät ^^



  • Sooo... Nach einiger Zeit (wo ich erst mal nen paar andere Fehler beseitigen musste) jetzt ein neuer (nicht sehr viel besserer) Vorschlag und verbunden damit gleich ein Hilferuf nach Links oder Erklärungen oder so was ^^

    ausgabe.hpp:

    #include <iostream>
    #include "threads.hpp"
    
    namespace my
    {
    	class my_cout : private threads_simple, public std::ostream
    		{
    			public:
    				my_cout (void);
    				const std::ostream& operator << (const std::ostream &ausgabe);
    		};
    };
    

    ausgabe.cpp:

    my::my_cout::my_cout (void)	: threads_simple ()//, std::ostream (std::cout)
    	{};
    
    const std::ostream& my::my_cout::operator << (const std::ostream &ausgabe)
    	{
    		lock (); //aus threads_simple
    		std::cout << ausgabe; //"normale" ausgabe
    		unlock (); //aus threads_simple
    		return ausgabe;
    	};
    

    Die Fehlermeldung (aber wie muss man std::ostream initiieren? (so, wie es da oben auskommentiert steht, hab ich es auch schon probiert, aber naja... 😕 ):

    f:\c\dahlia\konsole\dahlia_konsole_new\data\ausgabe.cpp(4) : error C2512: 'std::basic_ostream<_Elem,_Traits>': Kein geeigneter Standardkonstruktor verfügbar
            with
            [
                _Elem=char,
                _Traits=std::char_traits<char>
            ]
    

    Das würde das Problem vermutlich noch lange nicht lösen aber mich hoffentlich ein Stück weiterbringen... Mein eigtl Prob ist eigtl, dass ich bei Streams nur raten kann - ich weiß, dass es sie gibt und meistens, welche ich benutzen muss - aber hier müsste ich eben ma bissl mehr wissen ^^

    Bye und danke scho mal : >



  • Der Ostream-Ctor erwartet einen Streambuffer:
    http://www.cplusplus.com/reference/iostream/ostream/ostream.html



  • Nur mal am Rande, du hasst ne eigenwillige Auffassung was threadsicherheit bedeutet.
    Threadsicher bedeutet nicht, das die bib dir deine eingaben und ausgaben sortiert, sondern nur dass Du ueberhaupt in der lage sein kannst, das zeugs so zusammenzubauen wie du willst.

    Die STL und damit die iostreams sollten schon threadsicher sein, welche Impl nutzt du denn ? (ja bei MS gabs mal ne version die war ned 100% threadsicher, das wurde aber gifixt).

    Wenn du wirklich das zeugs geordnet ausgeben willst, wuerd ich deine Threads in ihren eigenen Buffer(stringstream z.b.) schreibenlassen, und dann nur einen ! thread das zeugs aus den buffern zusammensammeln lassen und nach cout ueberfuehren. Wann was zusammengesammelt werden kann, solltest dann mit Evenst signalen oder aehnliche sachen loesen.

    Ciao ...



  • RHBaum schrieb:

    Wenn du wirklich das zeugs geordnet ausgeben willst, wuerd ich deine Threads in ihren eigenen Buffer(stringstream z.b.) schreibenlassen, und dann nur einen ! thread das zeugs aus den buffern zusammensammeln lassen und nach cout ueberfuehren. Wann was zusammengesammelt werden kann, solltest dann mit Evenst signalen oder aehnliche sachen loesen.

    Genau das hatte ich ja schon vorgeschlagen, war aber abgelehnt worden weil die Aenderung zu viel Arbeit bedeutet haette. Allerdings: ein verungluecktes Design nachtraeglich zu aendern ist eigentlich nie soviel Arbeit und Stress, wie mit dem verunglueckten Desgin zu leben und darauf noch weiter aufzubauen 😉



  • "Threadsicher bedeutet nicht, das die bib dir deine eingaben und ausgaben sortiert, sondern nur dass Du ueberhaupt in der lage sein kannst, das zeugs so zusammenzubauen wie du willst."
    Ok - das is mir klar - dann wars eben ein wenig unglücklich formuliert...
    Die Ausgabe nur über einen Thread und mit Events zu lösen hilft mir aber auch nicht bei dem Operator << - dann schreib ich eben so was in der Art:

    my::cout << "asd" << "sdf" << my_int_varialbe << std::endl;
    

    und hau es eben nicht gleich in den std::cout - Buffer sondern erst in nen Buffer eines anderen Threads, setz nen Event und der Thread gibt es dann eben aus... Die Frage ist eben, ob das irgendwelche Vorteile hat - ich glaube nämlich nicht - will da ja auch nicht so tun, als ob ich es besser wüsste, aber das Problem an sich besteht so ja immer noch -.-

    "Die STL und damit die iostreams sollten schon threadsicher sein, welche Impl nutzt du denn?"
    std::cout, std::cerr, std::clog nutze ich - threadsicher an sich stimmt schon - nur leider wird die Ausgabe dann eben immer gemischt (zumindest bei cout und ich denke auch bei clog - nur bei cerr _sollte_ es so gehen)

    Danke schon ma

    PS: std::stringstream geht aber anscheind auch nicht für const char, oder hab ich da was falsch verstanden?

    //EDIT
    so hab ichs jz atm ma probiert - und das einzige, was jz nicht geht, ist SOCKET, so weit ich das überblicke ^^

    class my_cerr : private threads_simple, public std::stringstream
    		{
    			public:
    				my_cerr (void) : threads_simple (), std::stringstream () {};
    				const std::stringstream& operator << (const std::stringstream &ausgabe)
    				{
    					lock ();
    					std::cerr << ausgabe; //denkt euch hier halt was anderes hin...
    					unlock ();
    					return ausgabe;
    				};
    		};
    


  • Wenn nur ein Thread Ausgabeanweisungen entgegennehmen kann, dann setzt du einen Lock, nimmst den kompletten Krempel den du ausgeben sollst entgegen, schiebst ihn in std::cout, flushst std::cout und löst den Lock auf. Alle anderen Threads die was ausgeben wollen müssen derweil auf den Lock (und damit auf den flush) warten und niemand kann dir was dazwischen spucken. Oder hab ich da was übersehen? Was du dann natürlich nicht machen kannst sind Aufrufe á la

    my::out << bla << "blubb" << 123;
    

    , weil das aufeinanderfolgende Aufrufe der op<< sind und der Thread nicht wissen kann, ob er zwischendurch den Lock aufheben soll. Zwei Möglichkeiten:

    1. Du setzt innerhalb des Threads den Lock nd musst deshalb immer die komplette Ausgabe in einem Stück rübergeben (vorher mit std::stringstream o.ä. zusammenschrauben)
    2. Du forderst den Lock vor einer Ausgabe von außerhalb an, kannst danach alles in Einzelteilen mit mehreren op<< an den Stream schicken und gibst den Lock dann jedes Mal wieder frei. Das händisch zu machen ist Fehleranfällig, irgendwann vergisst man sonst die Freigabe und nach ner weile wartet alles auf de vergessenen Lock. Deshalb würde ich es mit RAII machen: Baue eine Klasse, die im Ctor einen Lock auf den Ausgabe-Thread anfordert und sich dann eine Referenz auf dessen Ausgabestream besorgt. Im Dtor fulshst du den Stream und gibst den Lock wieder frei. Die Klasse könnte von std::ostream ableiden und dessen Methoden stumpf an den ostream des Ausgabethreads weiterleiten.


  • Genau das ist mein Problem : <
    Ich will ne jedes mal 3 Zeilen für ne Ausgabe schreiben... (á la WaitForSingleObject (...), std::cout << "blubb" << std::endl, SetEvent (...))
    ich wollte mir eben den Aufwand ersparen und habs jz zwar hinbekommen (mehr oder weniger schön - wird mir aber wahrscheinlich trotzdem nicht so viel nutzen - werd ich dann beim nächsten Test sehen, wenn ich die 15 (mir unbegreiflichen) Linker-Fehler wegbekomm habe - ich sollte mir angewöhnen, nicht nur einmal in der Woche zu compilieren und nicht immer alles auf einmal zu ändern - naja...

    byebye



  • Es gehn auch 2 Zeilen 😉

    class myout : public std::ostream {
      static Lock thelock; //ein Lock fuer alle
      std::ostream& os;
    
      //verbiete Kopien
      myout& operator=(myout const&);
      myout(myout const&);
    public:
      explicit myout(std::ostream& os = std::cout) : os(os) { 
        thelock.lock(); //nur ein Objekt zur Zeit kann den Lock bekommen
      }
      ~myout() {
        os.flush();
        thelock.unlock();
      }
    
      //ostream-member ueberschreiben, einfach alles an den referenz-stream weiterleiten
      ostream& operator<< (double& val ) {
        os << val; return *this;
      }
      /* usw. */
    };
    
    ///////Code irgendwo...////////////////
    void foo() {
      /* Berechnungen */
      { //interner scope-Block
        myout out; //holt sich den lock, alle anderen muessen warten!
        out << bla;
        out << "bubb" << 126 << std::endl;
        int a = 25;
        // weitere Berechnungen, andere threads warten evtl weiter auf den lock
        out << a;
      } //scope ende, out wird zerstoert und der lock freigegeben
    
      //Genug der Spielerei, output in 2 Zeilen:
    
      myout logfileout(std::ofstream("logfile.txt")); //wieder lock geholt
      logfileout << "foo beendet";
    } //logfileout geht aus dem scope -> lock wieder freigegeben
    


  • Danke - sehr schöner Vorschlag, find ich 🤡
    Leider gibts da nen Fehler (nicht nur meiner Meinung - das sieht auch der Compiler nicht anders ^^):

    class myout : public std::ostream
     {
    /*...*/
      explicit myout(std::ostream& os = std::cout) : os(os) //std::ostream (????)
       { 
         /**/
       };
     };
    

    Im CTor muss (müsste?! ^^) ja auch std::ostream initialisiert werden, wenn davon geerbt wird... Und das ist ja der Schritt, über den ich die ganze Zeit schon nur rumraten kann 😕
    danke trotzdem und hoffentlich auch danke noch mal ;o)

    byebye



  • ui. Offenbar hat hier keiner verstanden, wie die C++-IO-Streams funktionieren 😮.

    Wenn du ein "Threadsafe" std::cout haben willst, dann solltest du den stream_buf Threadsafe machen 🙄

    Tipp: Schau dir mal Boost.IOStreams an. Das ist ganz praktisch, wenn man die IO-Streams erweitern will.



  • RHBaum schrieb:

    Nur mal am Rande, du hasst ne eigenwillige Auffassung was threadsicherheit bedeutet.
    Threadsicher bedeutet nicht, das die bib dir deine eingaben und ausgaben sortiert, sondern nur dass Du ueberhaupt in der lage sein kannst, das zeugs so zusammenzubauen wie du willst.

    Die STL und damit die iostreams sollten schon threadsicher sein, welche Impl nutzt du denn ? (ja bei MS gabs mal ne version die war ned 100% threadsicher, das wurde aber gifixt).

    Aus reiner Neugier: inwiefern ist die STL denn threadsafe? kann ich davon ausgehen, dass ein push_back() atomar ist? Und falls ja: wuerde sich das nicht sehr negativ auf die Performance im Singlethreaded Betrieb auswirken?



  • warum sollte ein push_back nicht atomar sein?
    alles, was ich wissen will, ist doch, wie zum teufel der ctor von "std::ostream" ist - ich versteh zwar, dass was in der msdn steht usw., aber iwie kommt jedes mal, wenn ich iwas von ostream erben lasse wieder nen 'ungültiger ctor'-Fehler... -.-



  • leg dir mal n Bookmark auf die C++-Referenz oder auf cppreference.com oder eine andre Referenz deiner Wahl, da steht sowas drin 😉

    und ein nicht-atomares vector::push_back wuerde ich naiverweise erwarten, wenn vec.size() == vec.capacity =>
    - neuen Speicher alokieren
    - alte Werte rueberkopieren
    - neuen Wert hinten anhaengen

    Wuerd mich schon wundern, wenn das in jeder STL-Implementierung standardmaessig threadsafe (ohne overhead durch locks/mutexe/critical sections) ist, aber ich lass mich gern ueberraschen 🙂



    1. "- neuen Speicher alokieren"

    2. "- alte Werte rueberkopieren"

    3. "- neuen Wert hinten anhaengen"

    4. ok - hier könnte es zutreffen...

    5. soll er noch im 'alten' Speicher rumoperieren? ich glaube nicht...

    6. max. hier - aber das würde ich für komisch halten - warum sollte man mit so ner einfachen (und schnellen) operation denn warten?

    Naja - wie auch immer...
    'cppreference.com' kenn ich - nur leider bin ich entweder zu doof oder blind oder wie auch immer -.-



  • nimm boost::format^^


Anmelden zum Antworten