【问题标题】:write vs fprintf - why different and which is better?write vs fprintf - 为什么不同,哪个更好?
【发布时间】:2013-02-26 00:13:40
【问题描述】:

我最近开始根据 POSIX 1003.1c 学习 pthread 的奇妙之处。

PThreads 可能看起来很复杂,但它们基本上是我们在类中用来创建并行行为的简单线程:https://computing.llnl.gov/tutorials/pthreads/

在我还在学习的时候,我的老师给了我们一个 C 代码来玩弄:

/* 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;
}
    运行和编译说明(适用于 linux):
  • 运行命令:`sudo apt-get install build-essential`
  • 下载此代码(显然是 xD)
  • 使用以下命令编译:`gcc -D_REENTRANT filenName.c -lpthread`
  • 使用以下命令运行结果:`./a.out`

一切正常,但我不明白为什么我的输出顺序会因writefprintf 的使用而不同。

当我使用write 时,我会随机输出如下字母:

Starting process a
aaaaaaaaaaaaaaaaaaaaaaaaaaaaStarting process b
aaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

但是当我使用fprintf 时,我总是得到类似于以下内容的输出:

Starting process a
Starting process b
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaababbabaabaabaababbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

在这种情况下,文本“Starting process”总是首先出现,并且不会与输出的其余部分混合。为什么会这样?是不是因为write 非常快而fprintf 比较慢?

作为一名 C 程序员,我应该使用哪一个?为什么?

【问题讨论】:

  • 注释掉的fprintf() 行似乎完全错误。

标签: c pthreads printf


【解决方案1】:

write 是一个系统调用:它将给定的字符直接发送到操作系统,操作系统(理论上,并且通常在实践中)立即将它们发送到输出设备,例如屏幕或磁盘。

fprintf(和fwrite 以及任何带有FILE * 参数的东西)是一个库调用,它在发送之前缓冲或收集程序内部的数据。这允许它发送更大、更统一的数据块,从而提高效率。

您在write 中看到的是,每次调用都会导致线程切换,因为程序等待操作系统确认写入是否成功。当一个线程在等待时,另一个线程获得时间。

使用fprintf,它从未做过如此特别的事情。它实际上只是一个线程用a's 填充一个数组,直到它完成。操作系统在接收到填充的缓冲区(通过write)之前不会更聪明。然后由于第一个线程没有更多的工作,它运行第二个。如果您打印更多字符,您会看到fprintf 也会在块发送到操作系统时交错ab

至于“快”和“慢”,write 在发送其输出时更直接,但fprintf 在几乎所有其他方面都更快,是一般正确的选择(或fwrite 更类似于write)。

【讨论】:

  • +1 - 作为补充:writefwrite 设计用于写入二进制数据而不是字符串。 fprintf 用于字符串。
【解决方案2】:

Write 封装了一个内核调用,它没有被缓冲。它只是将 n 个字节从缓冲区复制到文件描述符。

fprintf 是缓冲的,它也是用来处理字符串并用参数替换各种 %d、%s 的,因此执行起来要复杂得多,必须解析它接收到的字符串。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-29
    • 2011-01-09
    • 2018-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多