A line-based thread-safe std::cerr for C++
What is the easiest way to create my own std::cerr
so that it is line-by-line thread-safe.
I am preferably looking for the code to do it.
What I need is so that a line of output
(terminated with std::endl
) generated by one thread stays as a line of output
when I actually see it on my console (and is not mixed with some other thread's output).
Solution: std::cerr
is much slower than cstdio. I prefer using fprintf(stderr, "The message")
inside of a CriticalSectionLocker
class whose constructor acquires a thread-safe lock and the destructor releases it.
c++ multithreading iostream stderr subclassing
add a comment |
What is the easiest way to create my own std::cerr
so that it is line-by-line thread-safe.
I am preferably looking for the code to do it.
What I need is so that a line of output
(terminated with std::endl
) generated by one thread stays as a line of output
when I actually see it on my console (and is not mixed with some other thread's output).
Solution: std::cerr
is much slower than cstdio. I prefer using fprintf(stderr, "The message")
inside of a CriticalSectionLocker
class whose constructor acquires a thread-safe lock and the destructor releases it.
c++ multithreading iostream stderr subclassing
1
How do you imagine creating a thread local buffer "hooked" intostd::cerr
would reduce buffering over a thread local buffer "outside", then writing full lines intostd::cerr
? A buffer's a buffer.std::ostringstream
is a typical general purpose approach for this.
– Tony Delroy
Dec 15 '10 at 3:46
3
Are you by any chance looking for a thread-safe logging library?
– yasouser
Dec 15 '10 at 3:47
1
I recently learnt about the log4cpp project (log4cpp.sourceforge.net). Not sure whether it provides what you are looking for!?!? Maybe worthwhile to check it out.
– yasouser
Dec 15 '10 at 4:01
your own iostream cerr implementation is potentially much more buggy than using a well-tested library like log4cpp
– Ken Bloom
Dec 15 '10 at 4:20
add a comment |
What is the easiest way to create my own std::cerr
so that it is line-by-line thread-safe.
I am preferably looking for the code to do it.
What I need is so that a line of output
(terminated with std::endl
) generated by one thread stays as a line of output
when I actually see it on my console (and is not mixed with some other thread's output).
Solution: std::cerr
is much slower than cstdio. I prefer using fprintf(stderr, "The message")
inside of a CriticalSectionLocker
class whose constructor acquires a thread-safe lock and the destructor releases it.
c++ multithreading iostream stderr subclassing
What is the easiest way to create my own std::cerr
so that it is line-by-line thread-safe.
I am preferably looking for the code to do it.
What I need is so that a line of output
(terminated with std::endl
) generated by one thread stays as a line of output
when I actually see it on my console (and is not mixed with some other thread's output).
Solution: std::cerr
is much slower than cstdio. I prefer using fprintf(stderr, "The message")
inside of a CriticalSectionLocker
class whose constructor acquires a thread-safe lock and the destructor releases it.
c++ multithreading iostream stderr subclassing
c++ multithreading iostream stderr subclassing
edited Nov 15 '18 at 11:37
vallismortis
3,684104366
3,684104366
asked Dec 15 '10 at 3:41
unixman83unixman83
4,66895391
4,66895391
1
How do you imagine creating a thread local buffer "hooked" intostd::cerr
would reduce buffering over a thread local buffer "outside", then writing full lines intostd::cerr
? A buffer's a buffer.std::ostringstream
is a typical general purpose approach for this.
– Tony Delroy
Dec 15 '10 at 3:46
3
Are you by any chance looking for a thread-safe logging library?
– yasouser
Dec 15 '10 at 3:47
1
I recently learnt about the log4cpp project (log4cpp.sourceforge.net). Not sure whether it provides what you are looking for!?!? Maybe worthwhile to check it out.
– yasouser
Dec 15 '10 at 4:01
your own iostream cerr implementation is potentially much more buggy than using a well-tested library like log4cpp
– Ken Bloom
Dec 15 '10 at 4:20
add a comment |
1
How do you imagine creating a thread local buffer "hooked" intostd::cerr
would reduce buffering over a thread local buffer "outside", then writing full lines intostd::cerr
? A buffer's a buffer.std::ostringstream
is a typical general purpose approach for this.
– Tony Delroy
Dec 15 '10 at 3:46
3
Are you by any chance looking for a thread-safe logging library?
– yasouser
Dec 15 '10 at 3:47
1
I recently learnt about the log4cpp project (log4cpp.sourceforge.net). Not sure whether it provides what you are looking for!?!? Maybe worthwhile to check it out.
– yasouser
Dec 15 '10 at 4:01
your own iostream cerr implementation is potentially much more buggy than using a well-tested library like log4cpp
– Ken Bloom
Dec 15 '10 at 4:20
1
1
How do you imagine creating a thread local buffer "hooked" into
std::cerr
would reduce buffering over a thread local buffer "outside", then writing full lines into std::cerr
? A buffer's a buffer. std::ostringstream
is a typical general purpose approach for this.– Tony Delroy
Dec 15 '10 at 3:46
How do you imagine creating a thread local buffer "hooked" into
std::cerr
would reduce buffering over a thread local buffer "outside", then writing full lines into std::cerr
? A buffer's a buffer. std::ostringstream
is a typical general purpose approach for this.– Tony Delroy
Dec 15 '10 at 3:46
3
3
Are you by any chance looking for a thread-safe logging library?
– yasouser
Dec 15 '10 at 3:47
Are you by any chance looking for a thread-safe logging library?
– yasouser
Dec 15 '10 at 3:47
1
1
I recently learnt about the log4cpp project (log4cpp.sourceforge.net). Not sure whether it provides what you are looking for!?!? Maybe worthwhile to check it out.
– yasouser
Dec 15 '10 at 4:01
I recently learnt about the log4cpp project (log4cpp.sourceforge.net). Not sure whether it provides what you are looking for!?!? Maybe worthwhile to check it out.
– yasouser
Dec 15 '10 at 4:01
your own iostream cerr implementation is potentially much more buggy than using a well-tested library like log4cpp
– Ken Bloom
Dec 15 '10 at 4:20
your own iostream cerr implementation is potentially much more buggy than using a well-tested library like log4cpp
– Ken Bloom
Dec 15 '10 at 4:20
add a comment |
5 Answers
5
active
oldest
votes
Here's a thread safe line based logging solution I cooked up at some point. It uses boost mutex for thread safety. It is slightly more complicated than necessary because you can plug in output policies (should it go to a file, stderr, or somewhere else?):
logger.h:
#ifndef LOGGER_20080723_H_
#define LOGGER_20080723_H_
#include <boost/thread/mutex.hpp>
#include <iostream>
#include <cassert>
#include <sstream>
#include <ctime>
#include <ostream>
namespace logger
namespace detail
template<class Ch, class Tr, class A>
class no_output
private:
struct null_buffer
template<class T>
null_buffer &operator<<(const T &)
return *this;
;
public:
typedef null_buffer stream_buffer;
public:
void operator()(const stream_buffer &)
;
template<class Ch, class Tr, class A>
class output_to_clog
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
public:
void operator()(const stream_buffer &s)
static boost::mutex mutex;
boost::mutex::scoped_lock lock(mutex);
std::clog << now() << ": " << s.str() << std::endl;
private:
static std::string now()
char buf[64];
const time_t tm = time(0);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tm));
return buf;
;
template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
class logger
typedef OutputPolicy<Ch, Tr, A> output_policy;
public:
~logger()
output_policy()(m_SS);
public:
template<class T>
logger &operator<<(const T &x)
m_SS << x;
return *this;
private:
typename output_policy::stream_buffer m_SS;
;
class log : public detail::logger<detail::output_to_clog>
;
#endif
Usage looks like this:
logger::log() << "this is a test" << 1234 << "testing";
note the lack of a 'n'
and std::endl
since it's implicit. The contents are buffered and then atomically output using the template specified policy. This implementation also prepends the line with a timestamp since it is for logging purposes. The no_output
policy is stricly optional, it's what I use when I want to disable logging.
add a comment |
This:
#define myerr(e) CiriticalSectionLocker crit; std::cerr << e << std::endl;
works on most compilers for the common case of myerr("ERR: " << message << number)
.
This presumes you don't want to use the<<
operator for formatting (e.g.cerr << "This log message has been printed " << ntimes << " times." << endl;
)
– Ken Bloom
Dec 15 '10 at 14:54
2
Hrm. I'm actually wrong about that, because I forgot temporarily how macros work. All you'd need to do to get formatting is calllerr("This log message has been printed " << ntimes << " times.")
and the text substitution would get it right.
– Ken Bloom
Dec 15 '10 at 18:53
add a comment |
Why not just create a locking class and use it where ever you want to do thread-safe IO?
class LockIO
static pthread_mutex_t *mutex;
public:
LockIO() pthread_mutex_lock( mutex );
~LockIO() pthread_mutex_unlock( mutex );
;
static pthread_mutex_t* getMutex()
pthread_mutex_t *mutex = new pthread_mutex_t;
pthread_mutex_init( mutex, NULL );
return mutex;
pthread_mutex_t* LockIO::mutex = getMutex();
Then you put any IO you want in a block:
std::cout <<"X is " <<x <<std::endl;
becomes:
LockIO lock;
std::cout <<"X is " <<x <<std::endl;
add a comment |
If available, osyncstream (C++20) solves this problem:
#include <syncstream> // C++20
std::osyncstream tout(std::cout);
std::osyncstream terr(std::cerr);
If the above feature is not available, here is a drop-in header file containing two macros for thread-safe writing to std::cout
and std::cerr
(which must share a mutex in order to avoid interleaving of output). These are based on two other answers, but I have made some changes to make it easy to drop into an existing code base. This works with C++11 and forward.
I've tested this with 4 threads on a 4-core processor, with each thread writing 25,000 lines per second to tout
and occasional output to terr
, and it solves the output interleaving problem. Unlike a struct-based solution, there was no measurable performance hit for my application when dropping in this header file. The only drawback I can think of is that since this relies on macros, they can't be placed into a namespace.
threadstream.h
#ifndef THREADSTREAM
#define THREADSTREAM
#include <iostream>
#include <sstream>
#include <mutex>
#define terr ThreadStream(std::cerr)
#define tout ThreadStream(std::cout)
/**
* Thread-safe std::ostream class.
*
* Usage:
* tout << "Hello world!" << std::endl;
* terr << "Hello world!" << std::endl;
*/
class ThreadStream : public std::ostringstream
public:
ThreadStream(std::ostream& os) : os_(os)
// copyfmt causes odd problems with lost output
// probably some specific flag
// copyfmt(os);
// copy whatever properties are relevant
imbue(os.getloc());
precision(os.precision());
width(os.width());
setf(std::ios::fixed, std::ios::floatfield);
~ThreadStream()
std::lock_guard<std::mutex> guard(_mutex_threadstream);
os_ << this->str();
private:
static std::mutex _mutex_threadstream;
std::ostream& os_;
;
std::mutex ThreadStream::_mutex_threadstream;
#endif
test.cc
#include <thread>
#include <vector>
#include <iomanip>
#include "threadstream.h"
void test(const unsigned int threadNumber)
tout << "Thread " << threadNumber << ": launched" << std::endl;
int main()
std::locale mylocale(""); // get global locale
std::cerr.imbue(mylocale); // imbue global locale
std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)
std::cout << std::fixed << std::setw(4) << std::setprecision(5);
std::cerr << std::fixed << std::setw(2) << std::setprecision(2);
std::vector<std::thread> threads;
for (unsigned int threadNumber = 0; threadNumber < 16; threadNumber++)
std::thread t(test, threadNumber);
threads.push_back(std::move(t));
for (std::thread& t : threads)
if (t.joinable())
t.join();
terr << std::endl << "Main: " << "Test completed." << std::endl;
return 0;
compiling
g++ -g -O2 -Wall -c -o test.o test.cc
g++ -o test test.o -pthread
output
./test
Thread 0: launched
Thread 4: launched
Thread 3: launched
Thread 1: launched
Thread 2: launched
Thread 6: launched
Thread 5: launched
Thread 7: launched
Thread 8: launched
Thread 9: launched
Thread 10: launched
Thread 11: launched
Thread 12: launched
Thread 13: launched
Thread 14: launched
Thread 15: launched
Main: Test completed.
Awesome, thanks!
– thc
Mar 12 at 18:41
add a comment |
An improvement (that doesn't really fit in a comment) on the approach in unixman's comment.
#define LOCKED_ERR
if(ErrCriticalSectionLocker crit = ErrCriticalSectionLocker());
else std::cerr
Which can be used like
LOCKED_ERR << "ERR: " << message << endl;
if ErrCriticalSectionLocker is implemented carefully.
But, I would personally prefer Ken's suggestion.
+1 for creative use of the lifecycle of temporaries. Could you provide an implementation ofErrCriticalSectionLocker
, becuase the semantics are very non-trivial?
– Ken Bloom
Dec 15 '10 at 14:55
Hmm. I see; You can use this method withoutparenthesis
but I see little point in that, since my C (I come from C background) programming style generally calls for parenthesis. Also,ErrCriticalSectionLocker
is confusing...
– unixman83
Jul 18 '11 at 9:00
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f4446484%2fa-line-based-thread-safe-stdcerr-for-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
Here's a thread safe line based logging solution I cooked up at some point. It uses boost mutex for thread safety. It is slightly more complicated than necessary because you can plug in output policies (should it go to a file, stderr, or somewhere else?):
logger.h:
#ifndef LOGGER_20080723_H_
#define LOGGER_20080723_H_
#include <boost/thread/mutex.hpp>
#include <iostream>
#include <cassert>
#include <sstream>
#include <ctime>
#include <ostream>
namespace logger
namespace detail
template<class Ch, class Tr, class A>
class no_output
private:
struct null_buffer
template<class T>
null_buffer &operator<<(const T &)
return *this;
;
public:
typedef null_buffer stream_buffer;
public:
void operator()(const stream_buffer &)
;
template<class Ch, class Tr, class A>
class output_to_clog
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
public:
void operator()(const stream_buffer &s)
static boost::mutex mutex;
boost::mutex::scoped_lock lock(mutex);
std::clog << now() << ": " << s.str() << std::endl;
private:
static std::string now()
char buf[64];
const time_t tm = time(0);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tm));
return buf;
;
template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
class logger
typedef OutputPolicy<Ch, Tr, A> output_policy;
public:
~logger()
output_policy()(m_SS);
public:
template<class T>
logger &operator<<(const T &x)
m_SS << x;
return *this;
private:
typename output_policy::stream_buffer m_SS;
;
class log : public detail::logger<detail::output_to_clog>
;
#endif
Usage looks like this:
logger::log() << "this is a test" << 1234 << "testing";
note the lack of a 'n'
and std::endl
since it's implicit. The contents are buffered and then atomically output using the template specified policy. This implementation also prepends the line with a timestamp since it is for logging purposes. The no_output
policy is stricly optional, it's what I use when I want to disable logging.
add a comment |
Here's a thread safe line based logging solution I cooked up at some point. It uses boost mutex for thread safety. It is slightly more complicated than necessary because you can plug in output policies (should it go to a file, stderr, or somewhere else?):
logger.h:
#ifndef LOGGER_20080723_H_
#define LOGGER_20080723_H_
#include <boost/thread/mutex.hpp>
#include <iostream>
#include <cassert>
#include <sstream>
#include <ctime>
#include <ostream>
namespace logger
namespace detail
template<class Ch, class Tr, class A>
class no_output
private:
struct null_buffer
template<class T>
null_buffer &operator<<(const T &)
return *this;
;
public:
typedef null_buffer stream_buffer;
public:
void operator()(const stream_buffer &)
;
template<class Ch, class Tr, class A>
class output_to_clog
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
public:
void operator()(const stream_buffer &s)
static boost::mutex mutex;
boost::mutex::scoped_lock lock(mutex);
std::clog << now() << ": " << s.str() << std::endl;
private:
static std::string now()
char buf[64];
const time_t tm = time(0);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tm));
return buf;
;
template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
class logger
typedef OutputPolicy<Ch, Tr, A> output_policy;
public:
~logger()
output_policy()(m_SS);
public:
template<class T>
logger &operator<<(const T &x)
m_SS << x;
return *this;
private:
typename output_policy::stream_buffer m_SS;
;
class log : public detail::logger<detail::output_to_clog>
;
#endif
Usage looks like this:
logger::log() << "this is a test" << 1234 << "testing";
note the lack of a 'n'
and std::endl
since it's implicit. The contents are buffered and then atomically output using the template specified policy. This implementation also prepends the line with a timestamp since it is for logging purposes. The no_output
policy is stricly optional, it's what I use when I want to disable logging.
add a comment |
Here's a thread safe line based logging solution I cooked up at some point. It uses boost mutex for thread safety. It is slightly more complicated than necessary because you can plug in output policies (should it go to a file, stderr, or somewhere else?):
logger.h:
#ifndef LOGGER_20080723_H_
#define LOGGER_20080723_H_
#include <boost/thread/mutex.hpp>
#include <iostream>
#include <cassert>
#include <sstream>
#include <ctime>
#include <ostream>
namespace logger
namespace detail
template<class Ch, class Tr, class A>
class no_output
private:
struct null_buffer
template<class T>
null_buffer &operator<<(const T &)
return *this;
;
public:
typedef null_buffer stream_buffer;
public:
void operator()(const stream_buffer &)
;
template<class Ch, class Tr, class A>
class output_to_clog
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
public:
void operator()(const stream_buffer &s)
static boost::mutex mutex;
boost::mutex::scoped_lock lock(mutex);
std::clog << now() << ": " << s.str() << std::endl;
private:
static std::string now()
char buf[64];
const time_t tm = time(0);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tm));
return buf;
;
template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
class logger
typedef OutputPolicy<Ch, Tr, A> output_policy;
public:
~logger()
output_policy()(m_SS);
public:
template<class T>
logger &operator<<(const T &x)
m_SS << x;
return *this;
private:
typename output_policy::stream_buffer m_SS;
;
class log : public detail::logger<detail::output_to_clog>
;
#endif
Usage looks like this:
logger::log() << "this is a test" << 1234 << "testing";
note the lack of a 'n'
and std::endl
since it's implicit. The contents are buffered and then atomically output using the template specified policy. This implementation also prepends the line with a timestamp since it is for logging purposes. The no_output
policy is stricly optional, it's what I use when I want to disable logging.
Here's a thread safe line based logging solution I cooked up at some point. It uses boost mutex for thread safety. It is slightly more complicated than necessary because you can plug in output policies (should it go to a file, stderr, or somewhere else?):
logger.h:
#ifndef LOGGER_20080723_H_
#define LOGGER_20080723_H_
#include <boost/thread/mutex.hpp>
#include <iostream>
#include <cassert>
#include <sstream>
#include <ctime>
#include <ostream>
namespace logger
namespace detail
template<class Ch, class Tr, class A>
class no_output
private:
struct null_buffer
template<class T>
null_buffer &operator<<(const T &)
return *this;
;
public:
typedef null_buffer stream_buffer;
public:
void operator()(const stream_buffer &)
;
template<class Ch, class Tr, class A>
class output_to_clog
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
public:
void operator()(const stream_buffer &s)
static boost::mutex mutex;
boost::mutex::scoped_lock lock(mutex);
std::clog << now() << ": " << s.str() << std::endl;
private:
static std::string now()
char buf[64];
const time_t tm = time(0);
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tm));
return buf;
;
template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> >
class logger
typedef OutputPolicy<Ch, Tr, A> output_policy;
public:
~logger()
output_policy()(m_SS);
public:
template<class T>
logger &operator<<(const T &x)
m_SS << x;
return *this;
private:
typename output_policy::stream_buffer m_SS;
;
class log : public detail::logger<detail::output_to_clog>
;
#endif
Usage looks like this:
logger::log() << "this is a test" << 1234 << "testing";
note the lack of a 'n'
and std::endl
since it's implicit. The contents are buffered and then atomically output using the template specified policy. This implementation also prepends the line with a timestamp since it is for logging purposes. The no_output
policy is stricly optional, it's what I use when I want to disable logging.
answered Dec 15 '10 at 22:08
Evan TeranEvan Teran
67.9k19157221
67.9k19157221
add a comment |
add a comment |
This:
#define myerr(e) CiriticalSectionLocker crit; std::cerr << e << std::endl;
works on most compilers for the common case of myerr("ERR: " << message << number)
.
This presumes you don't want to use the<<
operator for formatting (e.g.cerr << "This log message has been printed " << ntimes << " times." << endl;
)
– Ken Bloom
Dec 15 '10 at 14:54
2
Hrm. I'm actually wrong about that, because I forgot temporarily how macros work. All you'd need to do to get formatting is calllerr("This log message has been printed " << ntimes << " times.")
and the text substitution would get it right.
– Ken Bloom
Dec 15 '10 at 18:53
add a comment |
This:
#define myerr(e) CiriticalSectionLocker crit; std::cerr << e << std::endl;
works on most compilers for the common case of myerr("ERR: " << message << number)
.
This presumes you don't want to use the<<
operator for formatting (e.g.cerr << "This log message has been printed " << ntimes << " times." << endl;
)
– Ken Bloom
Dec 15 '10 at 14:54
2
Hrm. I'm actually wrong about that, because I forgot temporarily how macros work. All you'd need to do to get formatting is calllerr("This log message has been printed " << ntimes << " times.")
and the text substitution would get it right.
– Ken Bloom
Dec 15 '10 at 18:53
add a comment |
This:
#define myerr(e) CiriticalSectionLocker crit; std::cerr << e << std::endl;
works on most compilers for the common case of myerr("ERR: " << message << number)
.
This:
#define myerr(e) CiriticalSectionLocker crit; std::cerr << e << std::endl;
works on most compilers for the common case of myerr("ERR: " << message << number)
.
edited Dec 18 '10 at 1:47
answered Dec 15 '10 at 5:01
unixman83unixman83
4,66895391
4,66895391
This presumes you don't want to use the<<
operator for formatting (e.g.cerr << "This log message has been printed " << ntimes << " times." << endl;
)
– Ken Bloom
Dec 15 '10 at 14:54
2
Hrm. I'm actually wrong about that, because I forgot temporarily how macros work. All you'd need to do to get formatting is calllerr("This log message has been printed " << ntimes << " times.")
and the text substitution would get it right.
– Ken Bloom
Dec 15 '10 at 18:53
add a comment |
This presumes you don't want to use the<<
operator for formatting (e.g.cerr << "This log message has been printed " << ntimes << " times." << endl;
)
– Ken Bloom
Dec 15 '10 at 14:54
2
Hrm. I'm actually wrong about that, because I forgot temporarily how macros work. All you'd need to do to get formatting is calllerr("This log message has been printed " << ntimes << " times.")
and the text substitution would get it right.
– Ken Bloom
Dec 15 '10 at 18:53
This presumes you don't want to use the
<<
operator for formatting (e.g. cerr << "This log message has been printed " << ntimes << " times." << endl;
)– Ken Bloom
Dec 15 '10 at 14:54
This presumes you don't want to use the
<<
operator for formatting (e.g. cerr << "This log message has been printed " << ntimes << " times." << endl;
)– Ken Bloom
Dec 15 '10 at 14:54
2
2
Hrm. I'm actually wrong about that, because I forgot temporarily how macros work. All you'd need to do to get formatting is call
lerr("This log message has been printed " << ntimes << " times.")
and the text substitution would get it right.– Ken Bloom
Dec 15 '10 at 18:53
Hrm. I'm actually wrong about that, because I forgot temporarily how macros work. All you'd need to do to get formatting is call
lerr("This log message has been printed " << ntimes << " times.")
and the text substitution would get it right.– Ken Bloom
Dec 15 '10 at 18:53
add a comment |
Why not just create a locking class and use it where ever you want to do thread-safe IO?
class LockIO
static pthread_mutex_t *mutex;
public:
LockIO() pthread_mutex_lock( mutex );
~LockIO() pthread_mutex_unlock( mutex );
;
static pthread_mutex_t* getMutex()
pthread_mutex_t *mutex = new pthread_mutex_t;
pthread_mutex_init( mutex, NULL );
return mutex;
pthread_mutex_t* LockIO::mutex = getMutex();
Then you put any IO you want in a block:
std::cout <<"X is " <<x <<std::endl;
becomes:
LockIO lock;
std::cout <<"X is " <<x <<std::endl;
add a comment |
Why not just create a locking class and use it where ever you want to do thread-safe IO?
class LockIO
static pthread_mutex_t *mutex;
public:
LockIO() pthread_mutex_lock( mutex );
~LockIO() pthread_mutex_unlock( mutex );
;
static pthread_mutex_t* getMutex()
pthread_mutex_t *mutex = new pthread_mutex_t;
pthread_mutex_init( mutex, NULL );
return mutex;
pthread_mutex_t* LockIO::mutex = getMutex();
Then you put any IO you want in a block:
std::cout <<"X is " <<x <<std::endl;
becomes:
LockIO lock;
std::cout <<"X is " <<x <<std::endl;
add a comment |
Why not just create a locking class and use it where ever you want to do thread-safe IO?
class LockIO
static pthread_mutex_t *mutex;
public:
LockIO() pthread_mutex_lock( mutex );
~LockIO() pthread_mutex_unlock( mutex );
;
static pthread_mutex_t* getMutex()
pthread_mutex_t *mutex = new pthread_mutex_t;
pthread_mutex_init( mutex, NULL );
return mutex;
pthread_mutex_t* LockIO::mutex = getMutex();
Then you put any IO you want in a block:
std::cout <<"X is " <<x <<std::endl;
becomes:
LockIO lock;
std::cout <<"X is " <<x <<std::endl;
Why not just create a locking class and use it where ever you want to do thread-safe IO?
class LockIO
static pthread_mutex_t *mutex;
public:
LockIO() pthread_mutex_lock( mutex );
~LockIO() pthread_mutex_unlock( mutex );
;
static pthread_mutex_t* getMutex()
pthread_mutex_t *mutex = new pthread_mutex_t;
pthread_mutex_init( mutex, NULL );
return mutex;
pthread_mutex_t* LockIO::mutex = getMutex();
Then you put any IO you want in a block:
std::cout <<"X is " <<x <<std::endl;
becomes:
LockIO lock;
std::cout <<"X is " <<x <<std::endl;
edited Mar 6 '13 at 0:37
andr
14k103854
14k103854
answered Mar 6 '13 at 0:19
Daniel WisehartDaniel Wisehart
1,3971029
1,3971029
add a comment |
add a comment |
If available, osyncstream (C++20) solves this problem:
#include <syncstream> // C++20
std::osyncstream tout(std::cout);
std::osyncstream terr(std::cerr);
If the above feature is not available, here is a drop-in header file containing two macros for thread-safe writing to std::cout
and std::cerr
(which must share a mutex in order to avoid interleaving of output). These are based on two other answers, but I have made some changes to make it easy to drop into an existing code base. This works with C++11 and forward.
I've tested this with 4 threads on a 4-core processor, with each thread writing 25,000 lines per second to tout
and occasional output to terr
, and it solves the output interleaving problem. Unlike a struct-based solution, there was no measurable performance hit for my application when dropping in this header file. The only drawback I can think of is that since this relies on macros, they can't be placed into a namespace.
threadstream.h
#ifndef THREADSTREAM
#define THREADSTREAM
#include <iostream>
#include <sstream>
#include <mutex>
#define terr ThreadStream(std::cerr)
#define tout ThreadStream(std::cout)
/**
* Thread-safe std::ostream class.
*
* Usage:
* tout << "Hello world!" << std::endl;
* terr << "Hello world!" << std::endl;
*/
class ThreadStream : public std::ostringstream
public:
ThreadStream(std::ostream& os) : os_(os)
// copyfmt causes odd problems with lost output
// probably some specific flag
// copyfmt(os);
// copy whatever properties are relevant
imbue(os.getloc());
precision(os.precision());
width(os.width());
setf(std::ios::fixed, std::ios::floatfield);
~ThreadStream()
std::lock_guard<std::mutex> guard(_mutex_threadstream);
os_ << this->str();
private:
static std::mutex _mutex_threadstream;
std::ostream& os_;
;
std::mutex ThreadStream::_mutex_threadstream;
#endif
test.cc
#include <thread>
#include <vector>
#include <iomanip>
#include "threadstream.h"
void test(const unsigned int threadNumber)
tout << "Thread " << threadNumber << ": launched" << std::endl;
int main()
std::locale mylocale(""); // get global locale
std::cerr.imbue(mylocale); // imbue global locale
std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)
std::cout << std::fixed << std::setw(4) << std::setprecision(5);
std::cerr << std::fixed << std::setw(2) << std::setprecision(2);
std::vector<std::thread> threads;
for (unsigned int threadNumber = 0; threadNumber < 16; threadNumber++)
std::thread t(test, threadNumber);
threads.push_back(std::move(t));
for (std::thread& t : threads)
if (t.joinable())
t.join();
terr << std::endl << "Main: " << "Test completed." << std::endl;
return 0;
compiling
g++ -g -O2 -Wall -c -o test.o test.cc
g++ -o test test.o -pthread
output
./test
Thread 0: launched
Thread 4: launched
Thread 3: launched
Thread 1: launched
Thread 2: launched
Thread 6: launched
Thread 5: launched
Thread 7: launched
Thread 8: launched
Thread 9: launched
Thread 10: launched
Thread 11: launched
Thread 12: launched
Thread 13: launched
Thread 14: launched
Thread 15: launched
Main: Test completed.
Awesome, thanks!
– thc
Mar 12 at 18:41
add a comment |
If available, osyncstream (C++20) solves this problem:
#include <syncstream> // C++20
std::osyncstream tout(std::cout);
std::osyncstream terr(std::cerr);
If the above feature is not available, here is a drop-in header file containing two macros for thread-safe writing to std::cout
and std::cerr
(which must share a mutex in order to avoid interleaving of output). These are based on two other answers, but I have made some changes to make it easy to drop into an existing code base. This works with C++11 and forward.
I've tested this with 4 threads on a 4-core processor, with each thread writing 25,000 lines per second to tout
and occasional output to terr
, and it solves the output interleaving problem. Unlike a struct-based solution, there was no measurable performance hit for my application when dropping in this header file. The only drawback I can think of is that since this relies on macros, they can't be placed into a namespace.
threadstream.h
#ifndef THREADSTREAM
#define THREADSTREAM
#include <iostream>
#include <sstream>
#include <mutex>
#define terr ThreadStream(std::cerr)
#define tout ThreadStream(std::cout)
/**
* Thread-safe std::ostream class.
*
* Usage:
* tout << "Hello world!" << std::endl;
* terr << "Hello world!" << std::endl;
*/
class ThreadStream : public std::ostringstream
public:
ThreadStream(std::ostream& os) : os_(os)
// copyfmt causes odd problems with lost output
// probably some specific flag
// copyfmt(os);
// copy whatever properties are relevant
imbue(os.getloc());
precision(os.precision());
width(os.width());
setf(std::ios::fixed, std::ios::floatfield);
~ThreadStream()
std::lock_guard<std::mutex> guard(_mutex_threadstream);
os_ << this->str();
private:
static std::mutex _mutex_threadstream;
std::ostream& os_;
;
std::mutex ThreadStream::_mutex_threadstream;
#endif
test.cc
#include <thread>
#include <vector>
#include <iomanip>
#include "threadstream.h"
void test(const unsigned int threadNumber)
tout << "Thread " << threadNumber << ": launched" << std::endl;
int main()
std::locale mylocale(""); // get global locale
std::cerr.imbue(mylocale); // imbue global locale
std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)
std::cout << std::fixed << std::setw(4) << std::setprecision(5);
std::cerr << std::fixed << std::setw(2) << std::setprecision(2);
std::vector<std::thread> threads;
for (unsigned int threadNumber = 0; threadNumber < 16; threadNumber++)
std::thread t(test, threadNumber);
threads.push_back(std::move(t));
for (std::thread& t : threads)
if (t.joinable())
t.join();
terr << std::endl << "Main: " << "Test completed." << std::endl;
return 0;
compiling
g++ -g -O2 -Wall -c -o test.o test.cc
g++ -o test test.o -pthread
output
./test
Thread 0: launched
Thread 4: launched
Thread 3: launched
Thread 1: launched
Thread 2: launched
Thread 6: launched
Thread 5: launched
Thread 7: launched
Thread 8: launched
Thread 9: launched
Thread 10: launched
Thread 11: launched
Thread 12: launched
Thread 13: launched
Thread 14: launched
Thread 15: launched
Main: Test completed.
Awesome, thanks!
– thc
Mar 12 at 18:41
add a comment |
If available, osyncstream (C++20) solves this problem:
#include <syncstream> // C++20
std::osyncstream tout(std::cout);
std::osyncstream terr(std::cerr);
If the above feature is not available, here is a drop-in header file containing two macros for thread-safe writing to std::cout
and std::cerr
(which must share a mutex in order to avoid interleaving of output). These are based on two other answers, but I have made some changes to make it easy to drop into an existing code base. This works with C++11 and forward.
I've tested this with 4 threads on a 4-core processor, with each thread writing 25,000 lines per second to tout
and occasional output to terr
, and it solves the output interleaving problem. Unlike a struct-based solution, there was no measurable performance hit for my application when dropping in this header file. The only drawback I can think of is that since this relies on macros, they can't be placed into a namespace.
threadstream.h
#ifndef THREADSTREAM
#define THREADSTREAM
#include <iostream>
#include <sstream>
#include <mutex>
#define terr ThreadStream(std::cerr)
#define tout ThreadStream(std::cout)
/**
* Thread-safe std::ostream class.
*
* Usage:
* tout << "Hello world!" << std::endl;
* terr << "Hello world!" << std::endl;
*/
class ThreadStream : public std::ostringstream
public:
ThreadStream(std::ostream& os) : os_(os)
// copyfmt causes odd problems with lost output
// probably some specific flag
// copyfmt(os);
// copy whatever properties are relevant
imbue(os.getloc());
precision(os.precision());
width(os.width());
setf(std::ios::fixed, std::ios::floatfield);
~ThreadStream()
std::lock_guard<std::mutex> guard(_mutex_threadstream);
os_ << this->str();
private:
static std::mutex _mutex_threadstream;
std::ostream& os_;
;
std::mutex ThreadStream::_mutex_threadstream;
#endif
test.cc
#include <thread>
#include <vector>
#include <iomanip>
#include "threadstream.h"
void test(const unsigned int threadNumber)
tout << "Thread " << threadNumber << ": launched" << std::endl;
int main()
std::locale mylocale(""); // get global locale
std::cerr.imbue(mylocale); // imbue global locale
std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)
std::cout << std::fixed << std::setw(4) << std::setprecision(5);
std::cerr << std::fixed << std::setw(2) << std::setprecision(2);
std::vector<std::thread> threads;
for (unsigned int threadNumber = 0; threadNumber < 16; threadNumber++)
std::thread t(test, threadNumber);
threads.push_back(std::move(t));
for (std::thread& t : threads)
if (t.joinable())
t.join();
terr << std::endl << "Main: " << "Test completed." << std::endl;
return 0;
compiling
g++ -g -O2 -Wall -c -o test.o test.cc
g++ -o test test.o -pthread
output
./test
Thread 0: launched
Thread 4: launched
Thread 3: launched
Thread 1: launched
Thread 2: launched
Thread 6: launched
Thread 5: launched
Thread 7: launched
Thread 8: launched
Thread 9: launched
Thread 10: launched
Thread 11: launched
Thread 12: launched
Thread 13: launched
Thread 14: launched
Thread 15: launched
Main: Test completed.
If available, osyncstream (C++20) solves this problem:
#include <syncstream> // C++20
std::osyncstream tout(std::cout);
std::osyncstream terr(std::cerr);
If the above feature is not available, here is a drop-in header file containing two macros for thread-safe writing to std::cout
and std::cerr
(which must share a mutex in order to avoid interleaving of output). These are based on two other answers, but I have made some changes to make it easy to drop into an existing code base. This works with C++11 and forward.
I've tested this with 4 threads on a 4-core processor, with each thread writing 25,000 lines per second to tout
and occasional output to terr
, and it solves the output interleaving problem. Unlike a struct-based solution, there was no measurable performance hit for my application when dropping in this header file. The only drawback I can think of is that since this relies on macros, they can't be placed into a namespace.
threadstream.h
#ifndef THREADSTREAM
#define THREADSTREAM
#include <iostream>
#include <sstream>
#include <mutex>
#define terr ThreadStream(std::cerr)
#define tout ThreadStream(std::cout)
/**
* Thread-safe std::ostream class.
*
* Usage:
* tout << "Hello world!" << std::endl;
* terr << "Hello world!" << std::endl;
*/
class ThreadStream : public std::ostringstream
public:
ThreadStream(std::ostream& os) : os_(os)
// copyfmt causes odd problems with lost output
// probably some specific flag
// copyfmt(os);
// copy whatever properties are relevant
imbue(os.getloc());
precision(os.precision());
width(os.width());
setf(std::ios::fixed, std::ios::floatfield);
~ThreadStream()
std::lock_guard<std::mutex> guard(_mutex_threadstream);
os_ << this->str();
private:
static std::mutex _mutex_threadstream;
std::ostream& os_;
;
std::mutex ThreadStream::_mutex_threadstream;
#endif
test.cc
#include <thread>
#include <vector>
#include <iomanip>
#include "threadstream.h"
void test(const unsigned int threadNumber)
tout << "Thread " << threadNumber << ": launched" << std::endl;
int main()
std::locale mylocale(""); // get global locale
std::cerr.imbue(mylocale); // imbue global locale
std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)
std::cout << std::fixed << std::setw(4) << std::setprecision(5);
std::cerr << std::fixed << std::setw(2) << std::setprecision(2);
std::vector<std::thread> threads;
for (unsigned int threadNumber = 0; threadNumber < 16; threadNumber++)
std::thread t(test, threadNumber);
threads.push_back(std::move(t));
for (std::thread& t : threads)
if (t.joinable())
t.join();
terr << std::endl << "Main: " << "Test completed." << std::endl;
return 0;
compiling
g++ -g -O2 -Wall -c -o test.o test.cc
g++ -o test test.o -pthread
output
./test
Thread 0: launched
Thread 4: launched
Thread 3: launched
Thread 1: launched
Thread 2: launched
Thread 6: launched
Thread 5: launched
Thread 7: launched
Thread 8: launched
Thread 9: launched
Thread 10: launched
Thread 11: launched
Thread 12: launched
Thread 13: launched
Thread 14: launched
Thread 15: launched
Main: Test completed.
edited Nov 14 '18 at 17:23
answered Nov 13 '18 at 19:22
vallismortisvallismortis
3,684104366
3,684104366
Awesome, thanks!
– thc
Mar 12 at 18:41
add a comment |
Awesome, thanks!
– thc
Mar 12 at 18:41
Awesome, thanks!
– thc
Mar 12 at 18:41
Awesome, thanks!
– thc
Mar 12 at 18:41
add a comment |
An improvement (that doesn't really fit in a comment) on the approach in unixman's comment.
#define LOCKED_ERR
if(ErrCriticalSectionLocker crit = ErrCriticalSectionLocker());
else std::cerr
Which can be used like
LOCKED_ERR << "ERR: " << message << endl;
if ErrCriticalSectionLocker is implemented carefully.
But, I would personally prefer Ken's suggestion.
+1 for creative use of the lifecycle of temporaries. Could you provide an implementation ofErrCriticalSectionLocker
, becuase the semantics are very non-trivial?
– Ken Bloom
Dec 15 '10 at 14:55
Hmm. I see; You can use this method withoutparenthesis
but I see little point in that, since my C (I come from C background) programming style generally calls for parenthesis. Also,ErrCriticalSectionLocker
is confusing...
– unixman83
Jul 18 '11 at 9:00
add a comment |
An improvement (that doesn't really fit in a comment) on the approach in unixman's comment.
#define LOCKED_ERR
if(ErrCriticalSectionLocker crit = ErrCriticalSectionLocker());
else std::cerr
Which can be used like
LOCKED_ERR << "ERR: " << message << endl;
if ErrCriticalSectionLocker is implemented carefully.
But, I would personally prefer Ken's suggestion.
+1 for creative use of the lifecycle of temporaries. Could you provide an implementation ofErrCriticalSectionLocker
, becuase the semantics are very non-trivial?
– Ken Bloom
Dec 15 '10 at 14:55
Hmm. I see; You can use this method withoutparenthesis
but I see little point in that, since my C (I come from C background) programming style generally calls for parenthesis. Also,ErrCriticalSectionLocker
is confusing...
– unixman83
Jul 18 '11 at 9:00
add a comment |
An improvement (that doesn't really fit in a comment) on the approach in unixman's comment.
#define LOCKED_ERR
if(ErrCriticalSectionLocker crit = ErrCriticalSectionLocker());
else std::cerr
Which can be used like
LOCKED_ERR << "ERR: " << message << endl;
if ErrCriticalSectionLocker is implemented carefully.
But, I would personally prefer Ken's suggestion.
An improvement (that doesn't really fit in a comment) on the approach in unixman's comment.
#define LOCKED_ERR
if(ErrCriticalSectionLocker crit = ErrCriticalSectionLocker());
else std::cerr
Which can be used like
LOCKED_ERR << "ERR: " << message << endl;
if ErrCriticalSectionLocker is implemented carefully.
But, I would personally prefer Ken's suggestion.
answered Dec 15 '10 at 6:45
Chris HopmanChris Hopman
1,9021010
1,9021010
+1 for creative use of the lifecycle of temporaries. Could you provide an implementation ofErrCriticalSectionLocker
, becuase the semantics are very non-trivial?
– Ken Bloom
Dec 15 '10 at 14:55
Hmm. I see; You can use this method withoutparenthesis
but I see little point in that, since my C (I come from C background) programming style generally calls for parenthesis. Also,ErrCriticalSectionLocker
is confusing...
– unixman83
Jul 18 '11 at 9:00
add a comment |
+1 for creative use of the lifecycle of temporaries. Could you provide an implementation ofErrCriticalSectionLocker
, becuase the semantics are very non-trivial?
– Ken Bloom
Dec 15 '10 at 14:55
Hmm. I see; You can use this method withoutparenthesis
but I see little point in that, since my C (I come from C background) programming style generally calls for parenthesis. Also,ErrCriticalSectionLocker
is confusing...
– unixman83
Jul 18 '11 at 9:00
+1 for creative use of the lifecycle of temporaries. Could you provide an implementation of
ErrCriticalSectionLocker
, becuase the semantics are very non-trivial?– Ken Bloom
Dec 15 '10 at 14:55
+1 for creative use of the lifecycle of temporaries. Could you provide an implementation of
ErrCriticalSectionLocker
, becuase the semantics are very non-trivial?– Ken Bloom
Dec 15 '10 at 14:55
Hmm. I see; You can use this method without
parenthesis
but I see little point in that, since my C (I come from C background) programming style generally calls for parenthesis. Also, ErrCriticalSectionLocker
is confusing...– unixman83
Jul 18 '11 at 9:00
Hmm. I see; You can use this method without
parenthesis
but I see little point in that, since my C (I come from C background) programming style generally calls for parenthesis. Also, ErrCriticalSectionLocker
is confusing...– unixman83
Jul 18 '11 at 9:00
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f4446484%2fa-line-based-thread-safe-stdcerr-for-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
How do you imagine creating a thread local buffer "hooked" into
std::cerr
would reduce buffering over a thread local buffer "outside", then writing full lines intostd::cerr
? A buffer's a buffer.std::ostringstream
is a typical general purpose approach for this.– Tony Delroy
Dec 15 '10 at 3:46
3
Are you by any chance looking for a thread-safe logging library?
– yasouser
Dec 15 '10 at 3:47
1
I recently learnt about the log4cpp project (log4cpp.sourceforge.net). Not sure whether it provides what you are looking for!?!? Maybe worthwhile to check it out.
– yasouser
Dec 15 '10 at 4:01
your own iostream cerr implementation is potentially much more buggy than using a well-tested library like log4cpp
– Ken Bloom
Dec 15 '10 at 4:20