На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: JoeUser, 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)
Мои программные ништякиhttp://majestio.info
В общем и целом резюмирую.
Я не вижу препятствий, почему бы всё не решить методом, подобным как описано в маразмах. Но это другая архитектура, переписывать надо. В той реализации, как у тебя, 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;
    }
Мои программные ништякиhttp://majestio.info
Цитата 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) бесконтрольное.
В принципе и запись в файловый поток должна бы проверяться, а тут в просто в память.
Жесткач короче :)
Мои программные ништякиhttp://majestio.info
Цитата 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;
1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
0 пользователей:
Страницы: (4) 1 [2] 3 4  все


Рейтинг@Mail.ru
[ Script Execution time: 0,1731 ]   [ 20 queries used ]   [ Generated: 21.07.18, 09:19 GMT ]