无法在线程内用C打印?

wswtfjt7  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(110)

我创建了一个简单的sleepsort算法:

#include <stdio.h>
#include <time.h>
#include <pthread.h>

#define ARR_SIZE 10

void *sleepSort(void *arg) {
    usleep(1000 * *(int*) arg);
    printf("%d ", *(int*) arg);
    return NULL;
}

int main(void) {
    srand(time(NULL));
    int arr[ARR_SIZE];

    for (int i = 0; i < ARR_SIZE; i++)
        arr[i] = rand() % 100;

    pthread_t thr[ARR_SIZE];

    for (int i = 0; i < ARR_SIZE; i++)
        pthread_create(thr + i, NULL, sleepSort, (void *)(arr + i));

    getchar();

    return 0;
}

然而,当我从Linux控制台运行它时,在我输入一个新字符之前,什么都不打印。然而,我修改了我的程序,在每个printf上添加了一个换行符,它就像预期的那样工作了,我不明白为什么。

mzsu5hc0

mzsu5hc01#

默认情况下,stdout在连接到终端时是行缓冲的。只有在接收到换行符、缓冲区已满、手动刷新句柄或禁用缓冲时,才会向系统写入数据。在此之前,输出只是在缓冲区中累积。
所以你需要

  • 发送Line Feed,
printf( "%d\n", ... );
  • 手动刷新stdout
printf( "%d ", ... );
fflush( stdout );
  • 或者禁用stdout的缓冲。
setbuf( stdout, NULL );
  //or//
setvbuf( stdout, NULL, _IONBF, 0 );

默认情况下,stdout在连接到终端以外的设备时是完全缓冲的。这也是其他句柄的默认设置,无论它们是否连接到端子。这与行缓冲相同,只是行馈送不会导致刷新。

w6lpcovy

w6lpcovy2#

标准输出是缓冲的,你需要通过以下方式强制缓冲区刷新:

fflush(stdout);

或通过打印LF

printf("\n")

如果你想看到输出,你也可以禁用缓冲:

setvbuf(stdout, NULL, _IONBF, 0);

文件:setvbuf
您在godbolt上的程序('\n'将无法工作,因为它不是终端):https://godbolt.org/z/x4xT1M51e

gcxthw6b

gcxthw6b3#

然而,当我从Linux控制台运行它时,在我输入一个新字符之前,什么都不打印。然而,我修改了我的程序,在每个printf上添加了一个换行符,它就像预期的那样工作了,我不明白为什么。
printf()使用缓冲输出来保存系统调用,为了有效地做到这一点,stdio包默认情况下根据输出设备有几种方法来做到这一点。

  • stdout上,所有的stdio例程都使用一个缓冲区,当标准输出连接到一个非tty设备(文件、管道、套接字等)时,该缓冲区只刷新其内容。
  • stdout连接到一个物理tty(控制台,或/dev中的任何tty设备)时,它会切换到一种模式,只有当缓冲区完全填满或在输出上检测到'\n'字符时,它才刷新缓冲区。这是你观察到的行为。当你输入新的行字符时,输出会显示出来,而不是累积在缓冲区中。另外,当您调用一个输入例程来读取时(这不是通用的,但有些实现会这样做,以允许您打印不以换行符结尾的提示),首先会执行缓冲区刷新。这也仅在输出和输入与终端相关联时发生。
  • 当你为setbuff()指定no buffer的时候,输出是完全没有缓冲的,所以每次printf都会导致一些东西被写入标准输出。
setbuff(stdout, NULL);

如果不想更改默认值(我建议不要将stdout buffer设置为NULL,因为这样会严重影响性能),可以不使用换行符强制刷新缓冲区,而只是穿插调用

fflush(stdout);

写在你想写的地方
最后,回答你的问题,这样做的主要原因是性能。缓冲输出大大加快了I/O的速度,应该一直使用,除非需要某些特殊特性(如调试程序)。

相关问题