I have recently started learning the wonders of pthreads according to POSIX 1003.1c.
PThreads may seem complex, but they are basically simple threads that we use in the class to create parallel behavior: https://computing.llnl.gov/tutorials/pthreads/
As I am still learning, my teacher gave us a C code to toy with:
/* Creates two threads, one printing 10000 "a"s, the other printing
10000 "b"s.
Illustrates: thread creation, thread joining. */
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include "pthread.h"
void * process(void * arg)
{
int i;
fprintf(stderr, "Starting process %s\n", (char *) arg);
for (i = 0; i < 100; i++) {
write(1, (char *) arg, 1);
// fprintf(stdout, (char *) arg, 1);
}
return NULL;
}
int main()
{
int retcode;
pthread_t th_a, th_b;
void * retval;
retcode = pthread_create(&th_a, NULL, process, "a");
if (retcode != 0) fprintf(stderr, "create a failed %d\n", retcode);
retcode = pthread_create(&th_b, NULL, process, "b");
if (retcode != 0) fprintf(stderr, "create b failed %d\n", retcode);
retcode = pthread_join(th_a, &retval);
if (retcode != 0) fprintf(stderr, "join a failed %d\n", retcode);
retcode = pthread_join(th_b, &retval);
if (retcode != 0) fprintf(stderr, "join b failed %d\n", retcode);
return 0;
}
Everything works but I don't understand why my output order is different depending on the use of write
or fprintf
.
When I use write
I get a random output of letters like the following:
Starting process a
aaaaaaaaaaaaaaaaaaaaaaaaaaaaStarting process b
aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
But when I use fprintf
I always get the get an output similar to:
Starting process a
Starting process b
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababbabaabaabaababbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
In this case, the text "Starting process" always appears first and is not mixed with the rest of the output. Why is this happening? Is it because write
is very fast and fprintf
is slower?
As a C programmer, which one should I use and why?
printf doesn't necessarily call write every time. Rather, printf buffers its output. That is, it often stores its result in a memory buffer, only calling write when the buffer is full, or on some other conditions.
E.g. Write() could be used something into the system or into a program. While Standard Library functions are program specific, E.g. printf() will print something out but it will only be in GUI/command line and wont effect system.
fprintf writes a string. fwrite writes bytes. So in your first case, you're writing the bytes that represent an integer to the file; if its value is "4", the four bytes will be in the non-printable ASCII range, so you won't see them in a text editor.
There- fore, printf and fprintf are fully-buffered when writing to files.
write
is a system call: it sends the given characters directly to the operating system, which (in theory, and often in practice) sends them immediately to the output device such as the screen or disk.
fprintf
(and fwrite
and anything that takes a FILE *
argument) is a library call, which buffers, or collects, the data inside your program before sending it. This allows it to send larger, more uniform chunks of data, which improves efficiency.
What you see with write
is that each call causes a thread switch as the program waits for the operating system to confirm whether the write succeeded. When one thread is waiting, the other thread gets time.
With fprintf
, it never does anything so exceptional. It's actually just one thread filling an array with a
's until it's done. The operating system is none the wiser until it receives the filled buffer (via write
). Then since the first thread has no more work, it runs the second. If you printed more characters, you would see fprintf
also interleave a
's and b
's as the chunks get sent to the operating system.
As for "fast" and "slow", write
is more immediate in sending its output, but fprintf
is faster in pretty much every other way and is the general correct choice (or fwrite
which is more similar to write
).
Write wraps a kernel call, and it's not buffered. It just copies n bytes from the buffer to the file descriptor.
fprintf is buffered and also it is meant to do string processing and replace the various %d, %s with the parameters, so it is much more complex to execute for this reason, having to parse the string that it receives.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With