Strange output when I use pthread and printf

I am writing a program using pthread .

Environment: windows 7, CYGWIN_NT-6.1 i686 Cygwin, gcc (GCC) 4.5.3

Source

 #include<stdio.h> #include<pthread.h> void *th_func(void *p) { int iLoop = 0; for(iLoop = 0;iLoop<100;iLoop++) { printf("Thread Thread Thread Thread\n"); } return; } int main() { int iLoop = 0; pthread_t QueThread; printf("Main : Start Main\n"); printf("Main : Start Create Thread\n"); pthread_create(&QueThread,NULL,th_func,NULL); printf("Main : End Create Thread\n"); for(iLoop = 0;iLoop<100;iLoop++) { printf("Main Main Main Main\n"); } pthread_join(QueThread,NULL); printf("Main : End Main\n"); printf("---------------\n"); return 0; } 

When I compile the source code, there are no warnings and errors, but the output looks strange.

Part of this conclusion

 Main : Start Main Main : Start Create Thread Thread Thread Thread ThreThread Thread Thread Thread Main Main Main Main Thread Thread Thread Thread Main Main Main Main 

I want to know the cause of this phenomenon.

On this output, Main : End Create Thread not printed completely. And on line 3, the new line \n at the end of "Thread Thread Thread Thread\n" disappears.

Is everything output like this? This does not happen every time, but happens once.

If I use a mutex to safely call printf , it seems that the look is disabled.

POSIX says printf is thread safe and, according to Cygwin.com, cygwin provides a posix style API. However, there is an unexpected exit.

Is printf really thread safe?

I ran the same program 100 times on Linux (Ubuntu), and this conclusion did not happen.

In addition, I did not understand the reason why some of the output words disappeared.

+5
c pthreads printf
Nov 02 '12 at 6:13
source share
5 answers

It looks like it could be a bug in Cygwin, or something is incorrectly configured. Several answers here show that "thread safe" only promises that a function is not harmful to the program, and that thread safety does not necessarily mean that the function is "atomic". But, as far as I know, POSIX does not formally define "thread safety" (if anyone has a pointer to such a definition, send it in a comment).

However, not only POSIX indicates that printf() is thread safe, POSIX also indicates that:

All functions that reference objects (FILE *) must behave as if they used flockfile () and funlockfile () internally to obtain ownership of these objects (FILE *).

Since printf() implicitly referencing the stdout FILE* object, all calls to printf() must be atomic with respect to each other (and any other function that uses stdout ).

Please note that this may not be true for other systems, but in my experience, this is true for many multi-threaded systems.

+3
Nov 02 '12 at 7:01
source share

The POSIX standard has features like putc_unlocked() , where the comment says:

The versions of the getc() , getchar() , putc() and putchar() , respectively, are called getc_unlocked() , getchar_unlocked() , putc_unlocked() and putchar_unlocked() , which are functionally equivalent to the original versions, except that they are not must be implemented in a thread-safe manner. They can only be used safely in the area protected by flockfile() (or ftrylockfile() ) and funlockfile() . These functions can be safely used in a multi-threaded program if and only if they are called when the calling thread owns an object ( FILE * ), as is the case after a successful call to the flockfile() or ftrylockfile() functions.

This clearly indicates that low-level single-character I / O functions are typically thread safe. However, this also indicates that the level of detail is a single character output operation. The printf() specification says:

The characters generated by fprintf() and printf() print as if fputc() was called.

And for putc() it says:

The putc() function should be equivalent to fputc() , except that if it is implemented as a macro, it can evaluate the stream more than once, so the argument should never be an expression with side effects.

The fputc() page does not say anything about thread safety, so you will have to look elsewhere for this information.

Another section describes threads and says:

All functions defined by this POSIX.1-2008 volume must be thread safe, except that the following functions must not be thread safe.

And the following list includes the functions *_unlocked() .

So, printf() and fputc() should be thread safe, but recording with printf() is done “as if” on fputc() , so the alternation of output between streams can be at the character level, which is more or less consistent with what do you see. If you want to make printf() calls without interlacing, you will need to use flockfile() and funlockfile() to give you ownership of stdout when funlockfile() executed. Similarly for fprintf() . You can easily write the fprintf_locked() function to achieve this result:

 int fprintf_locked(FILE *fp, const char *format, ...) { flockfile(fp); va_list args; va_start(args, format); int rc = vfprintf(fp, format, args); va_end(args); funlockfile(fp); return rc; } 

You can insert fflush(fp) there if you want. You can also have vfprintf_locked() and have a function above the call that performs lock, format (reset), and unlock operations. I probably coded it somehow, trusting the compiler to embed the code, if that was appropriate and doable. Versioning with stdout also quite simple.

Note the snippet of the POSIX specification for flockfile() pointed out by Michael Burr in the answer:

All functions that reference objects ( FILE * ), except those that have names ending in _unlocked , should behave as if they use flockfile() and funlockfile() internally to obtain ownership of these objects ( FILE * ).

Besides the odd parentheses around FILE * , these lines affect all other standard I / O functions, but you should be aware that these lines exist on one of the less frequently used manual pages. So my fprintf_locked() function is not needed. If you find an aberrant implementation of fprintf() that does not lock the file, the fprintf_locked() function can be used fprintf_locked() , but this should only be done under protest - the library should do it for you anyway.

+4
Nov 02 '12 at 7:15
source share

Just because a function is thread safe does not mean that it is atomic.

In your case, if you want your output not to alternate, you need to use a mutex to ensure that only one thread calls printf at a time.

0
Nov 02 '12 at 6:21
source share

Threads behave for this reason. If threads were running one after the other, and not "at the same time" (in an alternating manner), there would be no point in this type of "concurrency". When you use mutexes, threads will be blocked according to your intention, and they will generate the expected result.

In addition, you write return; in the function that returns void * and this behavior is undefined, so anything may happen when your program starts.

0
Nov 02
source share

I will put this in a simple way, you have two threads that are trying to access the resource. And also there are no priority type checks or something like a mutex. Theoretically, threads without a mutex or priority are assigned randomly by resources. try creating two streams with one type of print yes and the other with print. You will find this unusual behavior. Also remember that the runtime for different threads in this case is different. If you try the same material with one stream that writes information to a file and another guy writing to the console. You will not encounter such a problem. Hope this helps ...

0
Nov 02
source share



All Articles