Klassenfunktion mit Parameter als Thread



  • @Schlangenmensch sagte in Klassenfunktion mit Parameter als Thread:

    std::lock_guard<std::mutex> lock(mutex);
    for (; !messages.empty(); messages.pop())
      stream << messages.front();
    

    Das ja eben nicht... du legst damit die gesamte Anwendung lahm, wenn der Stream nicht schnell genug ist.



  • @Schlangenmensch

    Ich habe das mal als Übung benutzt. Meine Lösung:

    
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <format>
    
    #include <mutex>
    #include <thread>
    #include <queue>
    
    using namespace std::chrono_literals;
    
    class clogging
    {
      private:
    	std::queue<std::string> mMsgQueue;
    	std::mutex mMutex;
    	std::condition_variable mCondition;
    	std::atomic_bool mRunning = false;
    
      public:
    	void start()
    	{
    	    std::unique_lock<std::mutex> lock(mMutex);
    
    	    mRunning = true;
    	    while (mRunning)
    	    {
    	        mCondition.wait(lock, [this] {
    	            return !mMsgQueue.empty() || !mRunning;
    	        });
    			if (!mMsgQueue.empty())
    			{
    				std::cout << "clogging>> " << mMsgQueue.front() << "\n";
    				mMsgQueue.pop();
    			}
    	    }
    	}
    
    	void addmessage(const std::string& msg)
    	{
    		{
    			std::lock_guard<std::mutex> lock(mMutex);
    
    			mMsgQueue.push(msg);			
    		}
    		mCondition.notify_one();
    	}
    
    	void stop()
    	{
    		mRunning = false;
    		mCondition.notify_one();
    	}
    };
    
    
    int main()
    {
    	clogging logging;
    	std::jthread t(&clogging::start, &logging);
    
    	for (int i = 0; i < 100; i++)
    	{
    		std::this_thread::sleep_for(25ms);
    		logging.addmessage(std::format("Hallo Welt: {}", i));
    		std::this_thread::sleep_for(25ms);
    	}
    	std::this_thread::sleep_for(10s);
    	logging.stop();
    	return 0;
    }
    
    


  • @Quiche-Lorraine Oh, mit std::condition_variable ist schicker, wobei ich ein RAII Lösung bevorzugen würde, damit man das stop nicht vergessen kann.

    @Lupus-SLE Wenn du sorge davor hast, dann hol halt immer nur eine Nachricht aus der Queue und log die und nicht alle bisher angelaufenen.



  • Man kann das Ganze ja auch periodisch lösen (code unvollständig, nur zur Information), dann wacht der Logger nur alle 500ms auf und macht die Ausgabe.

    #include <string>
    #include <thread>
    #include <chrono>
    #include <vector>
    
    class clogging
    {
       std::vector<std::string> messages_;
       std::mutex mutex_;
    public:
       clogging();
    
       void add_message( std::string const& msg )
       {
          std::lock_guard<std::mutex> lock(mutex_);
          messages_.push_back( message );
       }
    
    private:
       void run()
       {
          while( running() )
          {
             std::vector<std::string> messages;
             {
                std::lock_guard<std::mutex> lock(mutex_);
                messages.swap( messages_ );
             }         
             for( auto const& msg : messages )
             {
                std::cout << "clogging>> " << msg << "\n";
             }
             std::this_thread::sleep_for( std::chrono::milliseconds(500) );
          }
       }
    };
    

    Noch schöner wird's mit der condition_variable, wie schon von @Quiche-Lorraine gezeigt. Nachteil ist allerdings, dass der Thread träge auf Beendigung reagiert, das kriegt man aber hin, indem man statt 500ms vllt 50x 10ms wartet und dabei prüft, ob der Thread beendet wurde.



  • Btw... bevor die Schlacht weitergeht... geht es eigentlich um Log-Ausgaben, die tatsächlich später noch einmal gelesen, also angefasst werden - oder verschwinden diese einfach in irgendeinem Systemlog? Wenn letzteres der Fall, dann sind so viele Log-Ausgaben doch eigentlich ein Anti-Pattern.

    Es gibt doch in Linux diese goldene Regel, "Be quiet except in errors"... und die KI sagt dazu:

    Key Aspects of This Principle

    • Preventing "Alert Fatigue": By silencing routine success messages, only true errors stand out, reducing the likelihood of missing important failures.
    • CI/CD and Automation: In automated scripts or Continuous Integration (CI) steps, a "quiet" command (often achieved via --quiet or similar flags) ensures that a passing job produces no output, making failed jobs immediately obvious.
    • Reducing Noise: This principle helps differentiate between expected behavior (warnings/info) and unexpected behavior (errors).
    • The "Unless Explicitly Silenced" Exception: While errors should not pass silently, there are rare, deliberate cases where catching a specific exception and doing nothing ("suppressing" it) is intended behavior.


  • @Lupus-SLE Ich würde vermuten, es geht dem TE darum, irgendwas mit Threads zu machen und das Logging ist halt einfach ein Beispiel um damit zu experimentieren.



  • @Schlangenmensch sagte in Klassenfunktion mit Parameter als Thread:

    dann hol halt immer nur eine Nachricht aus der Queue und log die und nicht alle bisher angelaufenen

    Ich denke auch, das wäre dann am sinnvollsten 🙂 ... sofern man keinen Zwischencache haben möchte.


Anmelden zum Antworten