Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

write vs fprintf - why different and which is better?

Tags:

c

printf

pthreads

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;
}
    Instructions to run and compile (for linux):
  • Run command: `sudo apt-get install build-essential`
  • Donwload this code (obviously xD)
  • Use the following command to compile: `gcc -D_REENTRANT filenName.c -lpthread`
  • Run the result by using the command: `./a.out`

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?

like image 967
Flame_Phoenix Avatar asked Feb 26 '13 00:02

Flame_Phoenix


People also ask

Why is printf faster than write?

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.

What are some differences between write ()` and printf?

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.

Is fprintf the same as fwrite?

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.

Does fprintf buffer?

There- fore, printf and fprintf are fully-buffered when writing to files.


2 Answers

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).

like image 153
Potatoswatter Avatar answered Sep 21 '22 21:09

Potatoswatter


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.

like image 33
LtWorf Avatar answered Sep 22 '22 21:09

LtWorf