Variation Gain Resolution

I am trying to write an asynchronous registrar that takes variable arguments, which are then strung together using a variator stringer, and then placed in one separate queue from the same manufacturer.

I am stuck in my enqueue function of my log structure, which is as follows:

template <typename T>
std::string Log::stringer(T const & t){
    return boost::lexical_cast<std::string>(t);
}

template<typename T, typename ... Args>
std::string Log::stringer(T const & t, Args const & ... args){
    return stringer(t) + stringer(args...);
}

 template<typename T, typename ... Args>
 void Log::enqueue(T & t, Args & ... args){
     boost::function<std::string()> f 
        = boost::bind(&Log::stringer<T &, Args & ...>,this,
                      boost::ref(t),
                      boost::forward<Args>(args)...);
 /// the above statement fails to compile though if i use 'auto f' it works ->
 /// but then it is unclear to me what the signature of f really is ?                              

 // at this point i would like to post the functor f onto my asio::io_service, 
 // but not able to cause it not clear to me what the type of f is.
 // I think it should be of type boost::function<std::string()>

 }

Inside main (), I'm calling

  Log t_log;
  t_log.enqueue("hello"," world");
+4
source share
1 answer

My suggestion for the function you are asking about:

template <typename T, typename... Args> void enqueue(T &t, Args const&... args) {
    this->io_service->post([=]{ 
                auto s = stringer(t, args...);
                //std::fprintf(stderr, "%s\n", s.c_str()); 
            });
}

This works with GCC and Clang (GCC 4.9 or later due to a known issue with captured variant packages).

, , , , , .

Questionables

, :

  • std::forward<> ( , )
  • io_service?

    • ( )
    • ...
  • boost::function ? () ... f

  • , , ? , Undefined . . ,

    char const msg[] = "my message"; // perhaps some sprintf output
    l.enqueue(cat.c_str(), msg);
    

    c_str() enqueue msg .

  • bind, c++11 ( std::forward<> )?

  • (, ? - , , , () (, ..).

    , , , . , , ( ). /, n .

  • shared_ptr. , .get()

    scoped_ptr, ( ?). ( boost::optional<work>, .)

  • / . , , , , ( ).

    ,

  • . , , , , , , .

  • , do . GCC/MSVC ++ 03 (__thread), ++ 11 thread_local, . pop()

    thread_local std::string s;
    s.reserve(1000);
    s.resize(0);
    

    ( , pop() , .

    , pop()

  • , , , ... spinlock ?

    void push(std::string const &s) {
        while (std::atomic_flag_test_and_set_explicit(&this->lock, std::memory_order_acquire))
            ;
        while (!this->q->push(s))
            ;
        std::atomic_flag_clear_explicit(&this->lock, std::memory_order_release);
    }
    

Live On Coliru

#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/atomic.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/thread/thread.hpp>

/*
 * safe for use from a single thread only
 */
template <unsigned line_maxchars = 1000>
class Log {
  public:
    Log(std::string const &logFileName, int32_t queueSize)
      : fp(stderr), // std::fopen(logFileName.c_str(),"w")
        _shutdown(false),
        _thread(&Log::pop, this),
        _queue(queueSize)
    { }

    void pop() {
        std::string s;
        s.reserve(line_maxchars);

        struct timeval ts;
        while (!_shutdown) {
            while (_queue.pop(s)) {
                gettimeofday(&ts, NULL);
                std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str());
            }
            std::fflush(fp); // RECONSIDER HERE?
        }

        while (_queue.pop(s)) {
            gettimeofday(&ts, NULL);
            std::fprintf(fp, "%li.%06li %s\n", ts.tv_sec, ts.tv_usec, s.c_str());
        }
    }

    template <typename S, typename T> void stringer(S& stream, T const &t) {
        stream << t;
    }

    template <typename S, typename T, typename... Args>
    void stringer(S& stream, T const &t, Args const &... args) {
        stringer(stream, t);
        stringer(stream, args...);
    }

    template <typename T, typename... Args> void enqueue(T &t, Args const&... args) {
        thread_local char buffer[line_maxchars] = {};
        boost::iostreams::array_sink as(buffer);
        boost::iostreams::stream<boost::iostreams::array_sink> stream(as);

        stringer(stream, t, args...);

        auto output = as.output_sequence();
        push(std::string(output.first, output.second));
    }

    void push(std::string const &s) {
        while (!_queue.push(s));
    }

    ~Log() {
        _shutdown = true;
        _thread.join();

        assert(_queue.empty());
        std::fflush(fp);
        std::fclose(fp);

        fp = NULL;
    }

  private:
    FILE *fp;
    boost::atomic_bool _shutdown;

    boost::thread _thread;
    boost::lockfree::spsc_queue<std::string> _queue;
};

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    auto start = high_resolution_clock::now();

    {
        Log<> l("/tmp/junk.log", 1024);

        for (int64_t i = 0; i < 10; ++i) {
            l.enqueue("hello ", i, " world");
        }
    }

    std::cout << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "μs\n";
}

, . , .

Asio . . . . . . .

, , , ,

  • make array_sinks/buffers
+5

All Articles