Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.217.208.72] |
|
Страницы: (4) 1 [2] 3 4 все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Но это у тебя работает ? log << "param1" << 1 << "ololo" << L'\n'; log.flush(); ..<< L'\n'; log.flush(); из процедуры "operator<< (ios::endl)" ----- Ты ничего не перепутал ? \n - это LF. Если текстовый файл для LINUX этого достаточно, а для Виндус - нет. |
Сообщ.
#17
,
|
|
|
Цитата ЫукпШ @ Вот и вызови это Как? Вот смотри: https://ideone.com/1JFO4Z Как его вызвать? У меня не получается, можешь плз написать? Или скажи что куда нужно написать? Добавлено ЫукпШ, тут проблема в том, что вывод идет в классе WrappedStream, а метод flush у Logger; WrapperStream ничего не знает о Logger, так как он находится на уровне ниже Logger'а. Его использует Logger. |
Сообщ.
#18
,
|
|
|
Да я не хочу во всём это разбираться. Тем более, что я считаю всё это сложным и лишним. Добавлено Цитата Wound @ тут проблема в том, что вывод идет в классе WrappedStream, а метод flush у Logger; WrapperStream ничего не знает о Logger, так как он находится на уровне ниже Logger'а. Но судя по твоему вопросу ты архитектурно зашёл в тупик. |
Сообщ.
#19
,
|
|
|
Цитата ЫукпШ @ Но судя по твоему вопросу ты архитектурно зашёл в тупик. Да. Дело в том, что в принципе можно обойтись тем что есть, и вызывать каждый раз flush, или вернуть шаблонную функцию на вариадиках, которая занималась выводом во временный wostringstream, это все не проблема. Это все уже реализовано, и работает, но это использовать не очень удобно. Да, реализовать легко, а юзать не очень. С выводом в поток - сложная получается реализация, а использование простое. И почти получилось, нужно только наверное выспаться и взглянуть свежим взглядом на проблему. |
Сообщ.
#20
,
|
|
|
Цитата ЫукпШ @ Ты ничего не перепутал ? \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) |
Сообщ.
#21
,
|
|
|
В общем и целом резюмирую.
Я не вижу препятствий, почему бы всё не решить методом, подобным как описано в маразмах. Но это другая архитектура, переписывать надо. В той реализации, как у тебя, endl вообще не вызывается в log << "param1" << 1 << "ololo" << endl;, там только берётся указатель на endl. Использование этого указателя в лучшем случае происходит лишь во WrappedStream, где всё равно информация о Logger уже потеряна. Добавлено Что-то типа 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_; }; |
Сообщ.
#22
,
|
|
|
Цитата Qraizer @ В той реализации, как у тебя, endl вообще не вызывается в log << "param1" << 1 << "ololo" << endl;, там только берётся указатель на endl. Использование этого указателя в лучшем случае происходит лишь во WrappedStream, где всё равно информация о Logger уже потеряна. Ок, есть ли способы переписать мой вариант по другому, но чтобы семантика вызова не изменилась? Если есть - можно хоть пнуть в нужном направлении? Если нет, то в таком случае, я был лучшего мнения о новом С++. Добавлено Ладно, наверное нужно выспаться и пересмотреть заново этот вопрос. Наверное пока не буду заморачиваться, оставлю на будущее. Всем спасибо. |
Сообщ.
#23
,
|
|
|
Wound, а если вот в такой код немножко накидать лок-гвардов?
... или я не про то? #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; } |
Сообщ.
#24
,
|
|
|
Цитата Wound @ Э-э-э... уже. Не? Ок, есть ли способы переписать мой вариант по другому, но чтобы семантика вызова не изменилась? |
Сообщ.
#25
,
|
|
|
Все таки я ради принципа добил!
Что вы думаете о таком извращении? Не возникнет ли тут проблем никаких? #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; } } } #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; } |
Сообщ.
#26
,
|
|
|
Не могу заценить в полной мере, я на летнем корпоративе. Мой вариант немного другой и ИМХО попроще.
|
Сообщ.
#27
,
|
|
|
Цитата Qraizer @ Не могу заценить в полной мере, я на летнем корпоративе. Мой вариант немного другой и ИМХО попроще. Ну в твоем варианте у меня от количества шаблонов в глазах рябит Тут все просто, основная идея такая - кто первый зашел в operator <<, тот и захватывает мьютекс, так же сохраняется id потока, который захватил IO поток. В io::endl(внутри функции flush) поток захвативший IO поток, выгружает его в очередь, и оповещает остальные потоки о том, что он закончил с помощью условной переменной. |
Сообщ.
#28
,
|
|
|
Цитата Wound @ Что вы думаете о таком извращении? Чисто имхо - не нравится архитектура. Цитата Wound @ Не возникнет ли тут проблем никаких? Очевидная - одна, строка 40: m_stream << val; Запихивание данных в память (в std::ostringstream) бесконтрольное. В принципе и запись в файловый поток должна бы проверяться, а тут в просто в память. Жесткач короче |
Сообщ.
#29
,
|
|
|
Цитата JoeUser @ Очевидная - одна, строка 40: Так нельзя делать. Это ограничение. Цитата JoeUser @ Запихивание данных в память (в std::ostringstream) бесконтрольное. В каком смысле бесконтрольное? Цитата JoeUser @ В принципе и запись в файловый поток должна бы проверяться, а тут в просто в память. Не совсем понял. Что должно проверятся куда? Это не окончательная версия, это тестовый пример, который призван проверить работоспособность конкретного алгоритма, а не проверять что там с файлом. Добавлено Цитата JoeUser @ Жесткач короче А в чем жесткач? По поводу ограничения, ну можно в принципе вместо wait, написать wait_for, и flush вызвать в деструкторе(это уже где то в боевом логгере.) Добавлено Цитата JoeUser @ а тут в просто в память. Не просто в память, а в кеш память. В боевом после достижения определенного размера - кеш сбрасываеться в файл. |
Сообщ.
#30
,
|
|
|
Цитата Wound @ А в чем жесткач? Насколько я понял, у тебя формирование сообщения, блокирует все другие попытки записи в лог. И, если не будет вызвано flush, то навсегда. Лучше эту задачу решать так - есть однопоточный класс Message, с оператором <<, который форматирует сообщение в какой-нибудь stringstream, и есть Logger, который под блокировкой сохраняет Message в файл: 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; |