使用 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_out
和 tee 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
)。将变量显式初始化为零和 NULL
,getline
函数将分配所需的内存。将未初始化的局部(非静态)变量用于除初始化之外的任何其他内容也会导致未定义的行为。
可能是 getline
写入一些看似随机的内存导致崩溃的未定义行为。
我正在尝试在我的 C 程序中创建一个聊天界面。
该程序使用两个 fifos 与分支 xterm
运行 同时执行命令 cat fifo_out
和 tee 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
)。将变量显式初始化为零和 NULL
,getline
函数将分配所需的内存。将未初始化的局部(非静态)变量用于除初始化之外的任何其他内容也会导致未定义的行为。
可能是 getline
写入一些看似随机的内存导致崩溃的未定义行为。