На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (4) 1 [2] 3 4  все  ( Перейти к последнему сообщению )  
> Трабла с манипулятором , Вызывается не то и не там :(
    Цитата Wound @
    Цитата ЫукпШ @
    Ты знаешь какой тип у "io::endl" ?

    Это мой манипулятор, я его сам написал. Могу любой тип ему сделать :)

    Но это у тебя работает ?
    ExpandedWrap disabled
      log << "param1" << 1 << "ololo" << L'\n';
      log.flush();
    Вот и вызови это
    ExpandedWrap disabled
      ..<< L'\n';
      log.flush();

    из процедуры "operator<< (ios::endl)"
    -----
    Ты ничего не перепутал ?
    \n - это LF.
    Если текстовый файл для LINUX этого достаточно, а для Виндус - нет.
    Сообщение отредактировано: ЫукпШ -
      Цитата ЫукпШ @
      Вот и вызови это

      Как?
      Вот смотри: https://ideone.com/1JFO4Z
      Как его вызвать? У меня не получается, можешь плз написать? Или скажи что куда нужно написать?

      Добавлено
      ЫукпШ, тут проблема в том, что вывод идет в классе WrappedStream, а метод flush у Logger; WrapperStream ничего не знает о Logger, так как он находится на уровне ниже Logger'а. Его использует Logger.
        Цитата Wound @
        Как?
        Вот смотри: https://ideone.com/1JFO4Z

        Да я не хочу во всём это разбираться. Тем более, что я считаю всё это сложным и лишним.

        Добавлено
        Цитата Wound @
        тут проблема в том, что вывод идет в классе WrappedStream, а метод flush у Logger; WrapperStream ничего не знает о Logger, так как он находится на уровне ниже Logger'а.

        Но судя по твоему вопросу ты архитектурно зашёл в тупик.
        Сообщение отредактировано: ЫукпШ -
          Цитата ЫукпШ @
          Но судя по твоему вопросу ты архитектурно зашёл в тупик.

          Да. Дело в том, что в принципе можно обойтись тем что есть, и вызывать каждый раз flush, или вернуть шаблонную функцию на вариадиках, которая занималась выводом во временный wostringstream, это все не проблема. Это все уже реализовано, и работает, но это использовать не очень удобно. Да, реализовать легко, а юзать не очень. С выводом в поток - сложная получается реализация, а использование простое. И почти получилось, нужно только наверное выспаться и взглянуть свежим взглядом на проблему.
            Цитата ЫукпШ @
            Ты ничего не перепутал ?
            \n - это LF.
            Если текстовый файл для LINUX этого достаточно, а для Виндус - нет.

            Достаточно всегда!

            Пруф:
            Цитата
            A text stream is an ordered sequence of characters composed into lines (zero or more characters plus a terminating '\n'). Whether the last line requires a terminating '\n' is implementation-defined. Characters may have to be added, altered, or deleted on input and output to conform to the conventions for representing text in the OS (in particular, C streams on Windows OS convert \n to \r\n on output, and convert \r\n to \n on input)
              В общем и целом резюмирую.
              Я не вижу препятствий, почему бы всё не решить методом, подобным как описано в маразмах. Но это другая архитектура, переписывать надо. В той реализации, как у тебя, endl вообще не вызывается в log << "param1" << 1 << "ololo" << endl;, там только берётся указатель на endl. Использование этого указателя в лучшем случае происходит лишь во WrappedStream, где всё равно информация о Logger уже потеряна.

              Добавлено
              Что-то типа
              ExpandedWrap disabled
                    class Logger;
                 
                    struct WrappedStream
                    {
                /* ... */
                        WrappedStream(std::ostream& ostream, std::recursive_mutex& mutex, Logger& log)
                        : m_gstream( std::make_unique<GuardStream>(ostream, mutex)), logger(log)
                        {
                        }
                 
                        WrappedStream(const WrappedStream& rhs): logger(rhs.logger)
                        {
                            m_gstream.swap(rhs.m_gstream);
                        }
                /* ... */
                        WrappedStream operator<< (WrappedStream pFn(Logger&))
                        {
                            return pFn(logger);
                        }
                 
                        mutable std::unique_ptr<GuardStream> m_gstream;
                        Logger& logger;
                    };
                 
                    struct Logger
                    {
                /* ... */
                        WrappedStream flush()
                        {
                            return WrappedStream(ostream_, mutex_, *this) << "flush";
                        }
                 
                        template<typename T>
                        WrappedStream operator<<(const T& x)
                        {
                            return WrappedStream(ostream_, mutex_, *this) << x;
                        }
                 
                        std::ostream& ostream_;
                        std::recursive_mutex mutex_;
                    };
              И – да, мьютекс нужен рекурсивный.
                Цитата Qraizer @
                В той реализации, как у тебя, endl вообще не вызывается в log << "param1" << 1 << "ololo" << endl;, там только берётся указатель на endl. Использование этого указателя в лучшем случае происходит лишь во WrappedStream, где всё равно информация о Logger уже потеряна.

                Ок, есть ли способы переписать мой вариант по другому, но чтобы семантика вызова не изменилась? Если есть - можно хоть пнуть в нужном направлении?
                Если нет, то в таком случае, я был лучшего мнения о новом С++. :-?

                Добавлено
                Ладно, наверное нужно выспаться и пересмотреть заново этот вопрос. Наверное пока не буду заморачиваться, оставлю на будущее.
                Всем спасибо.
                Сообщение отредактировано: Wound -
                  Wound, а если вот в такой код немножко накидать лок-гвардов?
                  ... или я не про то? :-?

                  ExpandedWrap disabled
                    #include <iostream>
                    #include <fstream>
                     
                    using namespace std;
                     
                    class LoggedStream {
                      private:
                        ostream& out;
                      public:
                        LoggedStream(ostream& o):out(o){}
                        template<typename T>
                        const LoggedStream& operator<<(const T& v) const {
                          out << v;
                          return *this;
                        }
                        LoggedStream const& operator<<(std::ostream& (*func)(std::ostream&)) const {
                          func(out);
                          return *this;
                        }
                    };
                     
                    int main(int,char**) {
                      LoggedStream Log1(std::cout);
                      Log1 << 1 << " 2" << endl << 3 << " 4" << endl;
                      //
                      std::ofstream ofs("test.txt", std::ofstream::out);
                      LoggedStream Log2(ofs);
                      Log2 << 1 << " 2" << endl << 3 << " 4" << endl;
                    }
                    Цитата Wound @
                    Ок, есть ли способы переписать мой вариант по другому, но чтобы семантика вызова не изменилась?
                    Э-э-э... уже. Не?
                      Все таки я ради принципа добил!
                      Что вы думаете о таком извращении?
                      Не возникнет ли тут проблем никаких?
                      ExpandedWrap disabled
                        #pragma once
                         
                        #include <sstream>
                        #include <string>
                        #include <memory>
                        #include <mutex>
                        #include <iostream>
                        #include <fstream>
                        #include <atomic>
                        #include <condition_variable>
                        #include <concurrent_queue.h>
                         
                        namespace core
                        {
                            class Logger
                            {
                                using lock_t = std::unique_lock<std::mutex>;
                            public:
                                Logger()
                                : m_isFreeStream(true)
                                {
                                }
                         
                                Logger(Logger&&) = delete;
                                Logger(const Logger&) = delete;
                                Logger& operator=(Logger&&) = delete;
                                Logger& operator=(const Logger&) = delete;
                         
                                ~Logger() = default;
                         
                                template<typename T>
                                Logger& operator<< (T&& val)
                                {
                                    lock_t guard_mtx(m_gmtx);
                                    m_condvar.wait(guard_mtx, [this] { return m_isFreeStream.load() || m_owner_thread_id == std::this_thread::get_id(); });
                         
                                    m_isFreeStream.store(false);
                                    m_owner_thread_id = std::this_thread::get_id();
                                    
                                    m_stream << val;
                                    return *this;
                                }
                         
                                friend Logger& operator<<(Logger& os, Logger& (*Pfn)(Logger&));
                         
                                void flush()
                                {
                                    lock_t guard_mtx(m_gmtx);
                                    {
                                        m_stream.flush();
                                        m_queue.push(m_stream.str());
                                        std::ostringstream tmp;
                                        m_stream.swap(tmp);
                                        m_isFreeStream.store(true);
                                        std::thread::id tmpid;
                                        m_owner_thread_id = tmpid;
                                    }
                                    m_condvar.notify_one();
                                }
                         
                                void Save(const std::string& file)
                                {
                                    std::ofstream fout;
                                    fout.open(file, std::ios_base::out | std::ios_base::trunc);
                                    if (!fout.is_open())
                                        throw "Error: file not open";
                         
                                    while (m_queue.unsafe_size() > 0u)
                                    {
                                        std::string line;
                                        if (m_queue.try_pop(line))
                                            fout << line;
                                    }
                                    fout.close();
                                }
                         
                            private:
                                std::mutex m_gmtx;
                                std::atomic_bool m_isFreeStream;
                                std::ostringstream m_stream;
                                concurrency::concurrent_queue<std::string> m_queue;
                                std::condition_variable m_condvar;
                                std::thread::id m_owner_thread_id;
                            };
                         
                            Logger& operator<<(Logger& os, Logger& (*Pfn)(Logger&))
                            {
                                return Pfn(os);
                            }
                         
                            namespace io
                            {
                                inline Logger& endl(Logger& stream)
                                {
                                    stream << '\n';
                                    stream.flush();
                                    return stream;
                                }
                            }
                        }

                      ExpandedWrap disabled
                        #include "Logger.h"
                        #include <iostream>
                        #include <thread>
                        #include <vector>
                        #include <chrono>
                        #include <algorithm>
                         
                        void Test(core::Logger& logger, const std::string& message)
                        {
                            auto old = std::chrono::steady_clock::now();
                            while (true)
                            {
                                auto now = std::chrono::steady_clock::now();
                                auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - old).count();
                                if (elapsed > 5)
                                    break;
                         
                                if (elapsed > 1)
                                    elapsed = elapsed;
                         
                                logger << "Thread [" << std::this_thread::get_id() << "] put message:" << message << "elapsed time: " << elapsed << core::io::endl;
                            }
                        }
                         
                        int main()
                        {
                            core::Logger log;
                         
                            log << "Ololo" << core::io::endl;
                         
                            std::vector<std::thread> threads;
                         
                            std::string msg1 = " Message one ";
                            std::string msg2 = " Message two ";
                            std::string msg3 = " Message three ";
                            std::string msg4 = " Message four ";
                         
                            threads.emplace_back(Test, std::ref(log), std::ref(msg1));
                            threads.emplace_back(Test, std::ref(log), std::ref(msg2));
                            threads.emplace_back(Test, std::ref(log), std::ref(msg3));
                            threads.emplace_back(Test, std::ref(log), std::ref(msg4));
                         
                            std::for_each(threads.begin(), threads.end(), [](auto&& item) { item.join(); });
                         
                         
                            log.Save("test.log");
                            std::cout << "Done...";
                            std::cin.get();
                            return 0;
                        }
                      Сообщение отредактировано: Wound -
                        Не могу заценить в полной мере, я на летнем корпоративе. Мой вариант немного другой и ИМХО попроще.
                          Цитата Qraizer @
                          Не могу заценить в полной мере, я на летнем корпоративе. Мой вариант немного другой и ИМХО попроще.

                          Ну в твоем варианте у меня от количества шаблонов в глазах рябит :D
                          Тут все просто, основная идея такая - кто первый зашел в operator <<, тот и захватывает мьютекс, так же сохраняется id потока, который захватил IO поток.
                          В io::endl(внутри функции flush) поток захвативший IO поток, выгружает его в очередь, и оповещает остальные потоки о том, что он закончил с помощью условной переменной.
                            Цитата Wound @
                            Что вы думаете о таком извращении?

                            Чисто имхо - не нравится архитектура.
                            Цитата Wound @
                            Не возникнет ли тут проблем никаких?

                            Очевидная - одна, строка 40:
                            ExpandedWrap disabled
                              m_stream << val;

                            Запихивание данных в память (в std::ostringstream) бесконтрольное.
                            В принципе и запись в файловый поток должна бы проверяться, а тут в просто в память.
                            Жесткач короче :)
                              Цитата JoeUser @
                              Очевидная - одна, строка 40:

                              Так нельзя делать. Это ограничение.

                              Цитата JoeUser @
                              Запихивание данных в память (в std::ostringstream) бесконтрольное.

                              В каком смысле бесконтрольное?

                              Цитата JoeUser @
                              В принципе и запись в файловый поток должна бы проверяться, а тут в просто в память.

                              Не совсем понял. Что должно проверятся куда?

                              Это не окончательная версия, это тестовый пример, который призван проверить работоспособность конкретного алгоритма, а не проверять что там с файлом.

                              Добавлено
                              Цитата JoeUser @
                              Жесткач короче :)

                              А в чем жесткач?

                              По поводу ограничения, ну можно в принципе вместо wait, написать wait_for, и flush вызвать в деструкторе(это уже где то в боевом логгере.)

                              Добавлено
                              Цитата JoeUser @
                              а тут в просто в память.

                              Не просто в память, а в кеш память. В боевом после достижения определенного размера - кеш сбрасываеться в файл.
                                Цитата Wound @
                                А в чем жесткач?

                                Насколько я понял, у тебя формирование сообщения, блокирует все другие попытки записи в лог. И, если не будет вызвано flush, то навсегда.

                                Лучше эту задачу решать так - есть однопоточный класс Message, с оператором <<, который форматирует сообщение в какой-нибудь stringstream, и есть Logger, который под блокировкой сохраняет Message в файл:
                                ExpandedWrap disabled
                                  lass CLogger;
                                  class CMessage
                                  {
                                  public:
                                      CMessage(CLogger &logger)
                                      : m_logger(logger)
                                      {
                                      }
                                   
                                      ~CMessage()
                                      {
                                          Flush();
                                      }
                                   
                                      template <typename T>
                                      CMessage &operator <<(T &&val)
                                      {
                                          m_out << std::forward<T>(val);
                                          return *this;
                                      }
                                   
                                      void Flush() noexcept
                                      {
                                          m_logger.Flush(std::move(m_out));
                                      }
                                   
                                  protected:
                                      CLogger &m_logger;
                                      std::stringstream m_out;
                                  };
                                   
                                  class CLogger
                                  {
                                  public:
                                      CMessage Message()
                                      {
                                          return CMessage(*this);
                                      }
                                   
                                      void Flush(std::stringstream out) noexcept
                                      {
                                          std::lock_guard lock(m_mx);
                                          m_file << ...out....  << std::endl
                                      }
                                  protected:
                                   
                                      std::mutex m_mx;
                                      std::ofstream m_file;
                                  };
                                   
                                  ......................................
                                  CLogger log;
                                   
                                  .........
                                  log.Message() << 1 << 2 << 3;
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (4) 1 [2] 3 4  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0619 ]   [ 16 queries used ]   [ Generated: 28.03.24, 14:52 GMT ]