putting returns in printf changes code behaviour

Is there any reason that putting (or not putting) a \n in a printf
statement should change the way code behaves?

The best conclusion we can come up with is that it’s some kind of a
terminal problem, but even if it is, how do I write code and debug when I
can’t trust what’s on the screen?

I have a short program that spawns three threads, they each write something
to the screen, and exit.

If I have no \n’s anywhere in the code it behaves like I’d expect.

But as soon as I put \n’s, one line of text appears twice.

We tried putting two returns at the end of each line, and we still got the
mystery line twice but the first occurence of it had only one return at the
end.

I understand about fflushing and buffering and stuff so I’m not complaining
about the order of stuff apprearing. Just that sometimes, depending how
many \n’s I have, I see different output.

I can also make the dupicate statement move by adding printfs throughout
the code.

If this isn’t some kind of a known problem I’ll post my code with some run
results…

Dana

\

Dana Echtner \ Real-Time Systems Administrator
dana@ece.concordia.ca / ECE, Concordia University, Montreal, Canada

rw-rw-rw-: The file protection of the beast

“Dana Echtner” <dana@ece.concordia.ca> wrote in message
news:9lh44n$a51$1@inn.qnx.com

Is there any reason that putting (or not putting) a \n in a printf
statement should change the way code behaves?

The best conclusion we can come up with is that it’s some kind of a
terminal problem, but even if it is, how do I write code and debug when I
can’t trust what’s on the screen?

I have a short program that spawns three threads, they each write
something
to the screen, and exit.

If I have no \n’s anywhere in the code it behaves like I’d expect.

But as soon as I put \n’s, one line of text appears twice.

We tried putting two returns at the end of each line, and we still got the
mystery line twice but the first occurence of it had only one return at
the
end.

I understand about fflushing and buffering and stuff so I’m not
complaining
about the order of stuff apprearing. Just that sometimes, depending how
many \n’s I have, I see different output.

I can also make the dupicate statement move by adding printfs throughout
the code.

If this isn’t some kind of a known problem I’ll post my code with some run
results…

Please post it.

Dana

\

Dana Echtner \ Real-Time Systems Administrator
dana@ece.concordia.ca > / ECE, Concordia University, Montreal, Canada

rw-rw-rw-: The file protection of the beast

Mario Charest wrote:


Please post it.

This is the output:

ivanova(dana):~/assign1$ ./main
Creating channels
Spawing threads…
Server starting
Server finished
Producer starting
Producer finishes
Consumer starting
Consumer starting
Consumer finished

This is the source. I don’t understand why the “Consumer starting” string
is printed twice. If I take out every \n in the code, it gets printed only
once.

Thanks!

Dana


#include <stdio.h>
#include <sys/neutrino.h>
#include <sys/netmgr.h>
#include <pthread.h>

struct two_channels {
int consumer_chid;
int producer_chid;
};


void *server (void *two_channels);
void *consumer (void *consumer_channel_id);
void *producer (void producer_channel_id);


int main (int argc, char
argv[])
{

int consumer_channel_id;
int producer_channel_id;

struct two_channels producer_consumer_channels;

pthread_attr_t attr;


/* create two channels for the threads to use /
printf (“Creating channels\n”);
consumer_channel_id = ChannelCreate (0); /
consumer <–> server /
producer_channel_id = ChannelCreate (0); /
producer <–> server */

producer_consumer_channels.consumer_chid = consumer_channel_id;
producer_consumer_channels.producer_chid = producer_channel_id;


/* do thread init stuff */
pthread_attr_init ( &attr );
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);

/* spawn the threads */
printf(“Spawing threads…\n”);
pthread_create(NULL,&attr,server,(void *)&producer_consumer_channels);
pthread_create(NULL,&attr,producer,(void *)&producer_channel_id);
pthread_create(NULL,&attr,consumer,(void *)&consumer_channel_id);

/* printf (“Parent process finished\n”); */
return (NULL);
}

void *server (void *producer_consumer_channels)
{

int consumer_coid;
int producer_coid;

struct two_channels *channels;

printf (“Server starting\n”);
channels = (struct two_channels *) producer_consumer_channels;

/* attach to both channels since we’re going to be talking to both
threads */

consumer_coid =
ConnectAttach(ND_LOCAL_NODE,0,channels->consumer_chid,0,0);
producer_coid =
ConnectAttach(ND_LOCAL_NODE,0,channels->producer_chid,0,0);

printf (“Server finished\n”);
return(NULL);

}

void *consumer (void *consumer_channel_id)
{

int server_coid;
int consumer_chid;

consumer_chid = *(int )consumer_channel_id;


printf (“Consumer starting\n”);
/
attach to consumer<–>server channel */
server_coid = ConnectAttach(ND_LOCAL_NODE,0,consumer_chid,0,0);


printf (“Consumer finished\n”);
return(NULL);

}

void *producer (void *producer_channel_id)
{
int server_coid;
int producer_chid;

producer_chid = *(int )producer_channel_id;
/
attach to producer<–>server channel */

printf (“Producer starting\n”);
server_coid = ConnectAttach(ND_LOCAL_NODE,0,producer_chid,0,0);

printf (“Producer finishes\n”);
return(NULL);

}

On Mon, 20 Aug 2001 10:45:14 +0228, Dana Echtner
<dana@ece.concordia.ca> wrote:

This is because the main thread (implicitly) flushes and
closes the stdout too early (play with sleep() in main() and/or
consumer()). It should wait until the other threads finish printing.

[This is NOT caused by the lack of _NTO_SIDE_CHANNEL in
ConnectAttach(), as the symptoms remain when these calls are removed.]

ako

Mario Charest wrote:



Please post it.

This is the output:

ivanova(dana):~/assign1$ ./main
Creating channels
Spawing threads…
Server starting
Server finished
Producer starting
Producer finishes
Consumer starting
Consumer starting
Consumer finished

This is the source. I don’t understand why the “Consumer starting” string
is printed twice. If I take out every \n in the code, it gets printed only
once.

Thanks!

Dana


#include <stdio.h
#include <sys/neutrino.h
#include <sys/netmgr.h
#include <pthread.h

struct two_channels {
int consumer_chid;
int producer_chid;
};


void *server (void *two_channels);
void *consumer (void *consumer_channel_id);
void *producer (void producer_channel_id);


int main (int argc, char
argv[])
{

int consumer_channel_id;
int producer_channel_id;

struct two_channels producer_consumer_channels;

pthread_attr_t attr;


/* create two channels for the threads to use /
printf (“Creating channels\n”);
consumer_channel_id = ChannelCreate (0); /
consumer <–> server /
producer_channel_id = ChannelCreate (0); /
producer <–> server */

producer_consumer_channels.consumer_chid = consumer_channel_id;
producer_consumer_channels.producer_chid = producer_channel_id;


/* do thread init stuff */
pthread_attr_init ( &attr );
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);

/* spawn the threads */
printf(“Spawing threads…\n”);
pthread_create(NULL,&attr,server,(void *)&producer_consumer_channels);
pthread_create(NULL,&attr,producer,(void *)&producer_channel_id);
pthread_create(NULL,&attr,consumer,(void *)&consumer_channel_id);

/* printf (“Parent process finished\n”); */
return (NULL);
}

void *server (void *producer_consumer_channels)
{

int consumer_coid;
int producer_coid;

struct two_channels *channels;

printf (“Server starting\n”);
channels = (struct two_channels *) producer_consumer_channels;

/* attach to both channels since we’re going to be talking to both
threads */

consumer_coid =
ConnectAttach(ND_LOCAL_NODE,0,channels->consumer_chid,0,0);
producer_coid =
ConnectAttach(ND_LOCAL_NODE,0,channels->producer_chid,0,0);

printf (“Server finished\n”);
return(NULL);

}

void *consumer (void *consumer_channel_id)
{

int server_coid;
int consumer_chid;

consumer_chid = *(int )consumer_channel_id;


printf (“Consumer starting\n”);
/
attach to consumer<–>server channel */
server_coid = ConnectAttach(ND_LOCAL_NODE,0,consumer_chid,0,0);


printf (“Consumer finished\n”);
return(NULL);

}

void *producer (void *producer_channel_id)
{
int server_coid;
int producer_chid;

producer_chid = *(int )producer_channel_id;
/
attach to producer<–>server channel */

printf (“Producer starting\n”);
server_coid = ConnectAttach(ND_LOCAL_NODE,0,producer_chid,0,0);

printf (“Producer finishes\n”);
return(NULL);

}

Andrzej Kocon wrote:

On Mon, 20 Aug 2001 10:45:14 +0228, Dana Echtner
dana@ece.concordia.ca> > wrote:

This is because the main thread (implicitly) flushes and
closes the stdout too early (play with sleep() in main() and/or
consumer()). It should wait until the other threads finish printing.

You’re right, when main() waits for the threads to finish it works fine.
Thanks!

D.


Dana Echtner \ Real-Time Systems Administrator
dana@ece.concordia.ca / ECE, Concordia University, Montreal, Canada

rw-rw-rw-: The file protection of the beast

Dana Echtner <dana@ece.concordia.ca> wrote:

Andrzej Kocon wrote:

On Mon, 20 Aug 2001 10:45:14 +0228, Dana Echtner
dana@ece.concordia.ca> > wrote:

This is because the main thread (implicitly) flushes and
closes the stdout too early (play with sleep() in main() and/or
consumer()). It should wait until the other threads finish printing.

You’re right, when main() waits for the threads to finish it works fine.

Instead of waiting, it might be simpler for main() to call
pthread_exit().


Wojtek Lerch QNX Software Systems Ltd.

OK. Implicitly or expliticly doesn’t this mean there is something wrong
with the toilet. It’s not flushing properly.

“Dana Echtner” <dana@ece.concordia.ca> wrote in message
news:9m3fv7$fq6$1@inn.qnx.com

Andrzej Kocon wrote:

On Mon, 20 Aug 2001 10:45:14 +0228, Dana Echtner
dana@ece.concordia.ca> > wrote:

This is because the main thread (implicitly) flushes and
closes the stdout too early (play with sleep() in main() and/or
consumer()). It should wait until the other threads finish printing.

You’re right, when main() waits for the threads to finish it works
fine.
Thanks!

D.

Wojtek Lerch wrote:


You’re right, when main() waits for the threads to finish it
works fine.

Instead of waiting, it might be simpler for main() to call
pthread_exit().

I’m not sure what you mean. I do a pthread_join from the main parent for
each of the three threads and then just return. How could I use
pthread_exit instead?

Thanks…

D.


Dana Echtner \ Real-Time Systems Administrator
dana@ece.concordia.ca / ECE, Concordia University, Montreal, Canada

rw-rw-rw-: The file protection of the beast

Dana Echtner <dana@ece.concordia.ca> wrote:

Wojtek Lerch wrote:



You’re right, when main() waits for the threads to finish it
works fine.

Instead of waiting, it might be simpler for main() to call
pthread_exit().

I’m not sure what you mean. I do a pthread_join from the main parent for
each of the three threads and then just return. How could I use
pthread_exit instead?

Well, I must say I’m not sure what you’re unsure about…

In the code you originally posted, change the last line of main() from

return (NULL);

to

pthread_exit (NULL);

Or, if you don’t like compiler warnings, add the pthread_exit line just
before the return line.

Too simple? ::slight_smile:

Your problem is that returning from main() causes a call to exit(), and
apparently, exit() closes stdout without making sure that other threads
won’t try to use it before they die. The solution is to prevent main()
from returning before the other threads are done. You can do that by
either waiting until you know they are done, or by preventing main()
from returning at all. A call to pthread_exit() is a simple way of
making sure that main() won’t return, and that your program will exit
when all your threads are done.

\

Wojtek Lerch QNX Software Systems Ltd.

On Thu, 23 Aug 2001 16:41:12 -0700, “Bill Caroselli (Q-TPS)”
<qtps@earthlink.net> wrote:

OK. Implicitly or expliticly doesn’t this mean there is something wrong
with the toilet. It’s not flushing properly.

Implicitly. If it is flushing, it’s not thread safe (explicit

functions like printf() or fflush() are). If it is closing, shouldn’t
a program that writes to a closed descriptor fail instead?

Tempted I’ve chosen not to state it with Bill’s metaphor…
I like his sense of humor, still remember “Is QSSL in the sugar cane
business now?” for example.

ako

Andrzej Kocon <ako@box43.gnet.pl> wrote:

On Thu, 23 Aug 2001 16:41:12 -0700, “Bill Caroselli (Q-TPS)”
qtps@earthlink.net> > wrote:

OK. Implicitly or expliticly doesn’t this mean there is something wrong
with the toilet. It’s not flushing properly.

Implicitly. If it is flushing, it’s not thread safe (explicit
functions like printf() or fflush() are). If it is closing, shouldn’t
a program that writes to a closed descriptor fail instead?

If you call close() and then pass the fd to write(), then yes. Provided
that you don’t call open() in the meantime.

But the program in question does not call write() directly. It calls
printf() after stdout may have been closed by exit(). As far as I know,
using a FILE pointer after it’s been closed is undefined behaviour, pretty
much like dereferencing a pointer that has been passed to free().

\

Wojtek Lerch QNX Software Systems Ltd.

Wojtek Lerch wrote:

A call to pthread_exit() is a simple way of
making sure that main() won’t return, and that your program will exit
when all your threads are done.

Oh I see. In the help page for pthread_exit it says “Thread termination
doesn’t implicitly release any process resources such as mutexes or file
descriptors” so I guess the thing is that a return() will so exactly that.

In that case (using pthread_exit), the O/S will take care of cleaning up
when the last thread in that process exits?

Thanks for the help!

D.


Dana Echtner \ Real-Time Systems Administrator
dana@ece.concordia.ca / ECE, Concordia University, Montreal, Canada

rw-rw-rw-: The file protection of the beast

Dana Echtner <dana@ece.concordia.ca> wrote:

Wojtek Lerch wrote:

A call to pthread_exit() is a simple way of
making sure that main() won’t return, and that your program will exit
when all your threads are done.

Oh I see. In the help page for pthread_exit it says “Thread termination
doesn’t implicitly release any process resources such as mutexes or file
descriptors” so I guess the thing is that a return() will so exactly that.

I just noticed that out docs also say

The last thread in a process will be the main() thread, which exits
with main()'s return value.

I don’t know where that came from; I’m pretty sure that there’s no
requirement that you mustn’t return from main() or terminate the main
thread before any other threads have terminated.

In that case (using pthread_exit), the O/S will take care of cleaning up
when the last thread in that process exits?

POSIX promises that if the last thread in a process terminates, the
entire process terminates as if exit(0) was called. I don’t know why
our docs don’t say that…


Wojtek Lerch QNX Software Systems Ltd.

Wojtek Lerch <wojtek_l@yahoo.ca> wrote:

Dana Echtner <> dana@ece.concordia.ca> > wrote:
Wojtek Lerch wrote:

A call to pthread_exit() is a simple way of
making sure that main() won’t return, and that your program will exit
when all your threads are done.

Oh I see. In the help page for pthread_exit it says “Thread termination
doesn’t implicitly release any process resources such as mutexes or file
descriptors” so I guess the thing is that a return() will so exactly that.

I just noticed that out docs also say

The last thread in a process will be the main() thread, which exits
with main()'s return value.

I’m not sure that is actually accurate or clear.

I don’t know where that came from; I’m pretty sure that there’s no
requirement that you mustn’t return from main() or terminate the main
thread before any other threads have terminated.

You may terminate the “main” thread without affecting the other threads.

But, if you return from main(), that will cause _exit() to be called and
cause the whole process to go away. (I think this actually comes from
the C language definition, but I’m not sure.)

I’m not sure where it is documented, but I know we teach it in the
QNX6 course.

In that case (using pthread_exit), the O/S will take care of cleaning up
when the last thread in that process exits?

POSIX promises that if the last thread in a process terminates, the
entire process terminates as if exit(0) was called. I don’t know why
our docs don’t say that…

They probably should. Not sure where, though.

-David

QNX Training Services
dagibbs@qnx.com