使用 cat、tee 和 fifos 在多线程 C 程序中打印和读取 xterm

Print and read from xterm in a multithreaded C program using cat, tee and fifos

我正在尝试在我的 C 程序中创建一个聊天界面。 该程序使用两个 fifos 与分支 xterm 运行 同时执行命令 cat fifo_outtee fifo_in > /dev/null 进行通信。 然后打开一个线程读取 *fifo_in 中的输入 由于 tee 来自终端,同时另一个线程在 fifo_out 中打印消息,并且在 xterm 中显示内容。

一切似乎都运行良好...除非在终端中写入一些文本时打印了一条消息,将输入的文本分成两部分。这会导致段错误!

你知道为什么会这样吗?

这是一个最小的例子:

int open_terminal(pid_t *pid, int *pipe)
{
  mkfifo("fifo_in", 0600);
  mkfifo("fifo_out", 0600); 
  pid_t p = fork();
  int fd_in, fd_out;
  switch (p) {
    case -1:
      return -1;
    case 0:
        execlp("xterm", "xterm", "-e", "cat fifo_out & tee fifo_in > /dev/null", NULL);
        exit(EXIT_FAILURE);
        break;
    default:
        if ((fd_in = open("fifo_in", O_RDONLY)) == - 1)
          return -1;
        if ((fd_out = open("fifo_out", O_WRONLY)) == - 1)
          return -1;
        *pid = p;
        pipe[0] = fd_in; pipe[1] = fd_out;
        return 0;
  }
  return -1;
}


void *message_thread(void *args)
{
  int *fd_out = (int *)args;
  while (1) {
    dprintf(*fd_out, "You're awesome!\n");
    sleep(5);
  }
}


void *input_thread(void *args)
{
  int *fd_in = (int *)args;
  FILE *f = fdopen(*fd_in, "r");
  while (1) {
    size_t n;
    char *line;
    getline(&line, &n, f);
    printf("Read: %s", line);
    free(line);
    if(strcmp(line, "exit\n") == 0)
      return NULL;
  }
}


int main(int argc, char *argv[])
{
  pid_t pid;
  int pipe[2];
  if (open_terminal(&pid, pipe) == -1) {
    printf("Can't open terminal.\n");
    return 1;
  }
  pthread_t mt, it;
  pthread_create(&mt, NULL, message_thread, &pipe[1]);
  pthread_create(&it, NULL, input_thread, &pipe[0]);

  pthread_join(it, NULL);

  return 0;
}

为了重现我的条件,运行 程序输入一些文本,等到在您的文本之后打印出一些文本,然后再次输入并输入。

来自 input_thread 函数:

free(line);
if(strcmp(line, "exit\n") == 0)

首先释放 line 分配和指向的内存,然后立即使用该内存。这会导致 未定义的行为

这还不是全部,因为您将未初始化的指针和大小传递给 getline 函数,它实际上不会分配内存,因为未初始化的局部变量具有 不确定性值(它看起来是随机的,不太可能为零或 NULL)。将变量显式初始化为零和 NULLgetline 函数将分配所需的内存。将未初始化的局部(非静态)变量用于除初始化之外的任何其他内容也会导致未定义的行为。

可能是 getline 写入一些看似随机的内存导致崩溃的未定义行为。