I'm working on a MT program on a Linux box. I've realized that if I
print a lot of messages to stdout from multiple threads, I get some
bizarre results, such as stalling of a thread suddenly and coming
back to life again.. However sometimes the problem disappears when
I remove [or reduce] prints. Can it be because multiple thread
trying to get hold of stdout getting into bizarre race conditions?
Does anybody have any experience similar to this or any comments?
I'm putting this question forward since I tend to use prints [printf()]
for debugging and hate to look for a bug which is caused by this
"debugging technique"..
Erol Sahin
--
Neurobotics Laboratory Voice: +1-617-353-1347
Dept. Cognitive and Neural Systems Fax : +1-617-353-7755
Boston University E-mail: er...@cns.bu.edu
677 Beacon St. Boston, MA 02215 USA http://cns-web.bu.edu/~erol
I'm not aware of any problems with multiple threads writing to
stdout on Linux.
However, even if there are no problems, you may be seeing interleaved
output:
example:
printf("x=%d, y=%d\n", x, y);
there is no guarantee that x and y will appear on the same line
> In article <362F6FC0...@ms.com>, Boris Goldberg <bor...@ms.com> wrote:
> > I'm not aware of any problems with multiple threads writing to
> >stdout on Linux.
> >
> > However, even if there are no problems, you may be seeing interleaved
> >output:
> >
> > example:
> >
> > printf("x=%d, y=%d\n", x, y);
> >
> >there is no guarantee that x and y will appear on the same line
>
> Surely, printf() will lock the stream object (if you use the MT safe glibc2),
> no?
Although printf() can be used in a multi-threaded environment, there is no
guarantee that the output of two printf() statements in two threads won't be
mixed. The best thing you could do is to lock the file in which you want to
write, in your case being 'stdout'. You could replace printf() with something
like the following piece of code:
int rprintf(const char *format, ...)
{
register int len;
va_list args;
va_start(args, format);
flockfile(stdout);
len = vprintf(format, args);
va_end(args);
funlockfile(stdout);
return len;
}
If you are REALLY concerned about the perfomance, there is a better code:
int rprintf(const char *format)
{
char buf[65536];
register int i, len;
va_list args;
va_start(args, format);
flockfile(stdout);
len = vsprintf(buf, format, args);
for (i = 0; i < len; i++)
putc_unlocked((int)*(buf + i), stdout);
funlockfile(stdout);
va_end(args);
return len;
}
Nader
Not on Linux, or any other UNIX variant I've dealt with. UNIX is used
to it, even before threads. stdout on NT doesn't make sense unless it's
a console appliation.
For POSIX conformance, printf() must lock the process' stdio file stream. That is,
the output is "atomic". Thus, if two threads both call a single printf()
simultaneously, each output must be correct. E.g., for
printf ("%d, %d\n", 1, 2); printf ("%s, %s"\n", "abc",
"def");
you might get
1, 2
abc, def
or you might get
abc, def
1, 2
but no more "bizarre" variations. If you do, then the implementation you're using
is broken.
There is another level of complication, though, if you're talking about the
sequence of multiple printf()s, for example. E.g., if you have
printf ("%d", 1); printf ("%s", "abc");
printf (", %d\n", 2); printf (", %s\n", "def");
Then you might indeed get something like
abc1, def
, 2
POSIX adds an explicit stdio stream lock to avoid this problem, which you can
acquire using flockfile() and release using funlockfile(). For example, you could
correct that second example by coding it as
flockfile (stdout); flockfile (stdout);
printf ("%d", 1); printf ("%s", "abc");
printf (", %d\n", 2); printf (", %s\n", "def");
funlockfile (stdout); funlockfile (stdout);
Of course, if you write to the same file using stdio from separate processes,
there's no synchronization between them unless there are some guarantees about how
stdio generates the actual file descriptor write() calls from its internal
buffering. (And I don't believe their is.)
/---------------------------[ Dave Butenhof ]--------------------------\
| Compaq Computer Corporation bute...@zko.dec.com |
| 110 Spit Brook Rd ZKO2-3/Q18 http://members.aol.com/drbutenhof |
| Nashua NH 03062-2698 http://www.awl.com/cseng/titles/0-201-63392-2/ |
\-----------------[ Better Living Through Concurrency ]----------------/
< For POSIX conformance, printf() must lock the process' stdio file
stream. That is,
< the output is "atomic". Thus, if two threads both call a single
printf()
< simultaneously, each output must be correct. E.g., for
<
< printf ("%d, %d\n", 1, 2); printf ("%s, %s"\n", "abc",
< "def");
<
< you might get
<
< 1, 2
< abc, def
<
< or you might get
< abc, def
< 1, 2
<
< but no more "bizarre" variations. If you do, then the implementation
you're using
< is broken.
Hmmm. I do get interleaved output on Solaris 2.5.1 which made me
replace printf with sprintf+puts