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...);
});
}
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";
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>
template <unsigned line_maxchars = 1000>
class Log {
public:
Log(std::string const &logFileName, int32_t queueSize)
: fp(stderr),
_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);
}
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 . . . . . . .
, , , ,