Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Stream thread-safety

Reply
Thread Tools

Stream thread-safety

 
 
Yang Zhang
Guest
Posts: n/a
 
      02-12-2008
I know that std streams are not thread-safe (i.e., output can end up
becoming interleaved), but do they share mutable state? (At least in
libstdc++ 4.2 on Linux kernel 2.6.x?)

I just spent a long time tracking down a bug in my program where,
given enough threads, eventually all cout<<int would print in hex
rather than dec, even though I never used stream formatters. couts in
this program are called from multiple threads, and some couts around
the middle of my program ended up interleaved - couts before it are
fine, and later ones end up in hex. After removing the contentious
couts in the middle, the problem went away - no more hex.

Could this have been an effect of using the streams from multiple
threads? I've been searching a long time for memory bugs, but haven't
come up with anything. Thanks in advance for any hints.
 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      02-12-2008
On Feb 12, 7:35 pm, Yang Zhang <(E-Mail Removed)> wrote:
> I know that std streams are not thread-safe (i.e., output can
> end up becoming interleaved), but do they share mutable state?
> (At least in libstdc++ 4.2 on Linux kernel 2.6.x?)


That's very implementation defined. They certainly depend at
least a little on shared mutable state, since they use dynamic
memory.

It shouldn't matter, however. Unless there's an error in the
implementation, if the implementation is given as being usable
in a multithreaded environment (which is what thread-safe
means), it's not your problem. You only need to synchronize if
several threads are accessing the same stream.

> I just spent a long time tracking down a bug in my program where,
> given enough threads, eventually all cout<<int would print in hex
> rather than dec, even though I never used stream formatters. couts in
> this program are called from multiple threads, and some couts around
> the middle of my program ended up interleaved - couts before it are
> fine, and later ones end up in hex. After removing the contentious
> couts in the middle, the problem went away - no more hex.


Obviously, all accesses to cout must be synchronized externally
if cout is used by more than one thread. Otherwise, it's your
program which isn't thread safe, not cout. And just as
obviously, it is the responsibility of whoever modifies a
formatting flag to restore it after they've finished---and
before they free up any synchronization.

> Could this have been an effect of using the streams from
> multiple threads?


Not if the threads are using the object correctly. If each
thread acts as if it were the only thread using the resource,
however, anything could happen.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
 
Chris Thomasson
Guest
Posts: n/a
 
      02-13-2008

"James Kanze" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
On Feb 12, 7:35 pm, Yang Zhang <(E-Mail Removed)> wrote:
> I know that std streams are not thread-safe (i.e., output can
> end up becoming interleaved), but do they share mutable state?
> (At least in libstdc++ 4.2 on Linux kernel 2.6.x?)


That's very implementation defined. They certainly depend at
least a little on shared mutable state, since they use dynamic
memory.

It shouldn't matter, however. Unless there's an error in the
implementation, if the implementation is given as being usable
in a multithreaded environment (which is what thread-safe
means), [...]

Thread-Safe in what context? basic or strong?


 
Reply With Quote
 
Chris Thomasson
Guest
Posts: n/a
 
      02-13-2008
DAMN,SHI%$###!

The quoted text is totally screwed! Let me try and fix that nonsense bastar$
garbage:


"Chris Thomasson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed). ..
>
> "James Kanze" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
> On Feb 12, 7:35 pm, Yang Zhang <(E-Mail Removed)> wrote:
>> I know that std streams are not thread-safe (i.e., output can
>> end up becoming interleaved), but do they share mutable state?
>> (At least in libstdc++ 4.2 on Linux kernel 2.6.x?)

>
> That's very implementation defined. They certainly depend at
> least a little on shared mutable state, since they use dynamic
> memory.
>
> It shouldn't matter, however. Unless there's an error in the
> implementation, if the implementation is given as being usable
> in a multithreaded environment (which is what thread-safe
> means), [...]
>


Origin Question by CT in response to JK:

'Thread-Safe in what context? basic or strong?'







I so VERY sorry for the horrible syntax contained within my first response
to James Kanze within this thread!


;^(...

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      02-13-2008
On Feb 13, 6:51 am, "Chris Thomasson" <(E-Mail Removed)> wrote:

[...]
> Thread-Safe in what context? basic or strong?


I'm not familiar with those terms. Thread safe means,
basically, specifying how objects of the class must behave in a
multithreaded environment. If a class has a contract which
specifies what the user must do in a multithreaded environment,
it is thread safe. If it doesn't it isn't.

Obviously, since there is a contract, the user must uphold his
end of it as well, or you have undefined behavior. But "thread
safety" is largely a question of specification and
documentation, not of any particular code behavior. (Although I
suppose one could argue that if the contract said that all use
of the class must be synchronized externally, including use of
two different instances, that the class wasn't thread safe.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
Chris Thomasson
Guest
Posts: n/a
 
      02-13-2008
> "James Kanze" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
> > On Feb 13, 6:51 am, "Chris Thomasson" <(E-Mail Removed)> wrote:


[...]
> > Thread-Safe in what context? basic or strong?


> I'm not familiar with those terms. Thread safe means,
> basically, specifying how objects of the class must behave in a
> multithreaded environment.

[...]3

Darn... I was thinking of something else.


To the OP: in order to sync stream objects, you need a level of coarse-grain
external sync... *Or* here is a possible scheme that can increase
granularity and scalability:


http://groups.google.com/group/comp....0362ba3da48d0b






That being said:
__________________________________________________ ________________

http://www.boost.org/libs/smart_ptr/...m#ThreadSafety
the ("Any other simultaneous accesses result in undefined behavior." clause
contained therein means that shared_ptr, __as-is__, only follows
"basic/normal" thread-safety level)


Anyway, here is a fairly lengthy discussion on the difference between
basic/normal and strong thread-safety levels:


http://groups.google.com/group/comp....167941d32340c6
(this thread substitutes the thread-safety level term 'normal' with 'basic',
and vise-versa, as they are one in the same...)




For some working examples, the following code can handle both basic _and_
strong models:

http://groups.google.com/group/comp....763698da537d8f

http://home.comcast.net/~appcore/vzoom/refcount

http://atomic-ptr-plus.sourceforge.net

http://groups.google.com/group/comp....7609a5eff4a466
(POSIX based version)




Does that help clear some things up? If not, perhaps we can enlighten some
of the people who lurk around this group...


Any questions?

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      02-14-2008
On Feb 13, 10:49 am, "Chris Thomasson" <(E-Mail Removed)> wrote:
> > "James Kanze" <(E-Mail Removed)> wrote in message
> >news:(E-Mail Removed)...
> > > On Feb 13, 6:51 am, "Chris Thomasson" <(E-Mail Removed)> wrote:


> [...]
> > > Thread-Safe in what context? basic or strong?

> > I'm not familiar with those terms. Thread safe means,
> > basically, specifying how objects of the class must behave in a
> > multithreaded environment.


> [...]3


> Darn... I was thinking of something else.


> To the OP: in order to sync stream objects, you need a level
> of coarse-grain external sync... *Or* here is a possible
> scheme that can increase granularity and scalability:


> http://groups.google.com/group/comp..../msg/3f0362ba3...


That's one solution. For logging, I generally use a temporary
instance of a wrapper class---the constructor acquires the lock
(and also sets up various other things, like ensuring a time
stamp and other standard information appears at the start of the
record), and the final destructor frees it.

This has the advantage that the tests whether logging is active
at the desired level occur immediately---since they only access
read-only data, no lock is necessary, and if logging is not
active, no lock is acquired, nor is much of anything else done.
Which means that you can throw in debug logging statements all
over the place without noticeably slowing the application down.

> That being said:
> __________________________________________________ ________________


> http://www.boost.org/libs/smart_ptr/...m#ThreadSafety
> the ("Any other simultaneous accesses result in undefined
> behavior." clause contained therein means that shared_ptr,
> __as-is__, only follows "basic/normal" thread-safety level)


Note that shared_ptr pose a particular problem, because part of
the state is shared between different instances, and the client
code may not be aware of this. So you have to define your
guarantees very carefully.

> Anyway, here is a fairly lengthy discussion on the difference
> between basic/normal and strong thread-safety levels:


> http://groups.google.com/group/comp..../browse_frm/th...
> (this thread substitutes the thread-safety level term 'normal'
> with 'basic', and vise-versa, as they are one in the same...)


> For some working examples, the following code can handle both
> basic _and_ strong models:


> http://groups.google.com/group/comp..../browse_frm/th...


> http://home.comcast.net/~appcore/vzoom/refcount


> http://atomic-ptr-plus.sourceforge.net


> http://groups.google.com/group/comp..../browse_frm/th...
> (POSIX based version)


> Does that help clear some things up? If not, perhaps we can
> enlighten some of the people who lurk around this group...


> Any questions?


My main point was that whatever level you decide to implement
(and there are definitly more than two possible levels), what
makes code "thread safe" is the contract. Correctly documented
and implemented in consequence, even something like localtime()
is thread safe. (Posix, of course, chose the option to NOT make
any thread related contract apply here. A reasonable decision:
given the interface, any possible contract would be extremely
constraining on the user, and offering a new function, with a
contract more in line with the general principles of Posix, is
probably a better solution.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
Chris Thomasson
Guest
Posts: n/a
 
      02-14-2008
"James Kanze" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
On Feb 13, 10:49 am, "Chris Thomasson" <(E-Mail Removed)> wrote:
> > > "James Kanze" <(E-Mail Removed)> wrote in message
> > >news:(E-Mail Removed)...
> > > > On Feb 13, 6:51 am, "Chris Thomasson" <(E-Mail Removed)> wrote:


> > [...]
> > > > Thread-Safe in what context? basic or strong?
> > > I'm not familiar with those terms. Thread safe means,
> > > basically, specifying how objects of the class must behave in a
> > > multithreaded environment.


> > [...]3


> > Darn... I was thinking of something else.


> > To the OP: in order to sync stream objects, you need a level
> > of coarse-grain external sync... *Or* here is a possible
> > scheme that can increase granularity and scalability:


> > http://groups.google.com/group/comp..../msg/3f0362ba3...


> That's one solution. For logging, I generally use a temporary
> instance of a wrapper class---the constructor acquires the lock
> (and also sets up various other things, like ensuring a time
> stamp and other standard information appears at the start of the
> record), and the final destructor frees it.


Yup. You are referring to on-stack logger instance. I also want on-stack
log-producer, with a log-consumer thread on the other side. I don't want log
threads to execute final output commands. I want to use shared monotonic
counter to assign log-entries a ordered timestamp (e.g., think Lamport). The
log-consumer will be able to query it's registered threads for log info;
order any results; then output. Advantage being that you have low-overhead
log-producers, and totally ordered log output wrt the dedicated log-consumer
logic.



> This has the advantage that the tests whether logging is active
> at the desired level occur immediately---since they only access
> read-only data, no lock is necessary, and if logging is not
> active, no lock is acquired, nor is much of anything else done.
> Which means that you can throw in debug logging statements all
> over the place without noticeably slowing the application down.



BTW, can your read-only data wrt loging rules mutate over application
lifetime? The soultion above has per-thread rules, and a GUI application can
issue writes into the PDR reader-pattern based distributed log-info (e.g.,
per-thread info that is)...

The log-level validation information can be per-thread, or in a global
lock-free PDR protected data-structure (e.g., think RCU for a moment) such
that log-threads are readers and log-level mutation operations would execute
on writers. This would allow for a GUI application to dynamically set
logging rules on a pr-thread basis at runtime. Search
comp.programming.threads for PDR for more info...



Humm. Well, I would expecting very something like:
__________________________________________________ _________________
struct per_thread_log {
atomicword_rules level;
per_thread_log* next;
per_thread_log* prev;
};


struct per_thread {
per_thread_log* next;
atomicword_rules level;
single_producer_consumer_queue logq;
};


struct log_thread {
per_thread_logging rules;
per_thread_log* head;
per_thread_log* tail;
};


extern per_thread_log(int level, const char* format, ...);



#define LOG_LEVEL_BASIC()0x1
#define LOG_LEVEL_IMPORTANT()0x2
#define LOG_LEVEL_SHI%T_HIT_THE_FAN()0x4



void* some_thread(void* state) {
per_thread_log
log(LOG_LEVEL_BASIC(), "%s\n", "Started...");
if (foo(state) == ERROR_666()) {
log(LOG_LEVEL_SHI%T_HIT_THE_FAN(),
"%s\n", "Stopped...");
}
log(LOG_LEVEL_BASIC(), "%s\n", "Stopped...");
return 0;
}
__________________________________________________ _________________



[...]



 
Reply With Quote
 
Chris Thomasson
Guest
Posts: n/a
 
      02-14-2008
I accidently sent that too early!


"Chris Thomasson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
[...]

Fixing:

> Humm. Well, I would expecting very something like:
> __________________________________________________ _________________
> struct per_thread_log {
> atomicword_rules level;
> per_thread_log* next;
> per_thread_log* prev;
> };
>
>
> struct per_thread {
> per_thread_log* next;


^^^^^^^^^^^^^^^^^^^^^^

rename per_thread::next -> per_thread::cache;


> atomicword_rules level;
> single_producer_consumer_queue logq;
> };



>
>
> struct log_thread {
> per_thread_logging rules;
> per_thread_log* head;
> per_thread_log* tail;
> };

^^^^^^^^^^^^^^^^^^^^^^

the struct above needs to be removed.

[...]


An example implementation of my wait-free single-producer/consumer
per_thread queue which can hold per_thread_log objects in the example (e.g.,
'per_thread::logq' member) can be found here:

http://appcore.home.comcast.net



Any comments on this approach?

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      02-15-2008
On Feb 14, 11:40 am, "Chris Thomasson" <(E-Mail Removed)> wrote:
> "James Kanze" <(E-Mail Removed)> wrote in message


> news:(E-Mail Removed)...
> On Feb 13, 10:49 am, "Chris Thomasson" <(E-Mail Removed)>
> wrote:


> > > > "James Kanze" <(E-Mail Removed)> wrote in message
> > > >news:(E-Mail Removed)...
> > > > > On Feb 13, 6:51 am, "Chris Thomasson" <(E-Mail Removed)> wrote:
> > > [...]
> > > > > Thread-Safe in what context? basic or strong?
> > > > I'm not familiar with those terms. Thread safe means,
> > > > basically, specifying how objects of the class must behave in a
> > > > multithreaded environment.
> > > [...]3
> > > Darn... I was thinking of something else.
> > > To the OP: in order to sync stream objects, you need a level
> > > of coarse-grain external sync... *Or* here is a possible
> > > scheme that can increase granularity and scalability:
> > >http://groups.google.com/group/comp..../msg/3f0362ba3....

> > That's one solution. For logging, I generally use a temporary
> > instance of a wrapper class---the constructor acquires the lock
> > (and also sets up various other things, like ensuring a time
> > stamp and other standard information appears at the start of the
> > record), and the final destructor frees it.


> Yup. You are referring to on-stack logger instance. I also want on-stack
> log-producer, with a log-consumer thread on the other side. I don't want log
> threads to execute final output commands. I want to use shared monotonic
> counter to assign log-entries a ordered timestamp (e.g., think Lamport). The
> log-consumer will be able to query it's registered threads for log info;
> order any results; then output. Advantage being that you have low-overhead
> log-producers, and totally ordered log output wrt the dedicated log-consumer
> logic.


I've used both solutions at different times. With everything
done in the thread generating the log, you hold the lock a lot
longer, which can significantly affect latency. On the other
hand, in case of a crash or such, any logs triggered before the
crash in the thread which crashed are guaranteed to have been
output. It's a bit more reliable for debugging. (In once case,
the logging thread was in another process, communicating via
shared memory, precisely to avoid this problem while still using
the log-consumer thread model.)

> > This has the advantage that the tests whether logging is active
> > at the desired level occur immediately---since they only access
> > read-only data, no lock is necessary, and if logging is not
> > active, no lock is acquired, nor is much of anything else done.
> > Which means that you can throw in debug logging statements all
> > over the place without noticeably slowing the application down.


> BTW, can your read-only data wrt loging rules mutate over application
> lifetime? The soultion above has per-thread rules, and a GUI application can
> issue writes into the PDR reader-pattern based distributed log-info (e.g.,
> per-thread info that is)...


To date, I've not had to handle the case where the configuration
data could be changed while running AND we had multi-threading.
I've thought about it, though---the only solution that came to
mind immediately was to use a rwlock, held for read by all of
the threads, except when they are going to block; the thread
which will modify the configuration acquires it for write.

I don't want to use a mutex around the check whether a specific
level of logging is active; that check should be as fast as
possible.

> The log-level validation information can be per-thread, or in a global
> lock-free PDR protected data-structure (e.g., think RCU for a moment) such
> that log-threads are readers and log-level mutation operations would execute
> on writers. This would allow for a GUI application to dynamically set
> logging rules on a pr-thread basis at runtime. Search
> comp.programming.threads for PDR for more info...


If the need arises, I'll certainly research the topic; I'm sure
that there are better solutions than the one off the top of my
head. (There are a lot of issues that I've not investigated,
simply because I've not needed them yet.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Convert DVD with subtitle stream to DivX with same subtitle stream(selectable) malise Software 1 04-17-2007 09:15 AM
what is the different between byte stream and character stream? dolphin Java 6 03-18-2007 01:58 PM
get stream mode flags from an opened stream Alexander Korsunsky C++ 1 02-17-2007 10:38 AM
How to GET multi-word input from a *file* stream as opposed to a *console* stream? sherifffruitfly@gmail.com C++ 9 04-27-2006 04:14 PM
Doing readline in a thread from a popen4('rsync ...') stream blocks when the stream ends. Rasmusson, Lars Python 1 04-30-2004 08:10 AM



Advertisments