在C语言中,是否可能使用线程打开一个新的Linux终端?

7

在SO上似乎有很多与我所需不太相同但又很接近的问题。我正在尝试查看是否有一种方法可以从我的主程序中使用线程/子进程打开一个新的终端窗口(Linux),并使该线程/子进程拥有该新窗口。

总体目标概述:我将启动一个主程序,并通过 stdin 接收输入,如果我选择输入“启动助手”,它将生成一个新的终端窗口,该窗口本身可以与用户交互(stdin/stdout)。

因此,我想要做的是让主程序调用线程,让线程使用/拥有新的终端窗口,然后当线程消失并死亡时,关闭该窗口。

我知道这段代码不正确,但从概念上讲,我想要类似于这样的东西:

void * Runit()
{
    system("gnome-terminal"); //Would like to get a handle to this window
    while(1)
      printf("I'm the thread!!!\n"); //Would like to get this printed to the new window
}

int main()
{
    pthread_t child;
    pthread_create(&child, NULL, Runit, NULL);
    sleep(10);
    return 0; //Would like the child & its window to go away now.
}

这个要求很宽松,不需要可移植性,只是一个小型Linux工具,让我的生活更轻松。必须使用C代码,所以除非该脚本可以从C中运行,否则不要使用shell脚本。感谢任何帮助或其他想法。

编辑:

我知道在Linux终端上有文件句柄/dev/pts/x,我尝试过类似以下的代码:

system("gnome-terminal");
sleep(2); //let the file handle show up in /dev/pts
fp = fopen("/dev/pts/<new file handler number>");
fprintf(fp, "echo hi");

手柄正确打开,但终端没有显示任何内容。

这个窗口是否应该运行一个shell?还是仅用于用户输入? - parsifal
@parsifal - 只需要输入/输出(Ascii 菜单和响应),我不需要在新窗口中使用任何花哨的 shell 脚本。 - Mike
1
这是经典的 fork()execv()wait() 代码。线程是不必要的。 - Dave
@Dave - 除非我弄错了,否则这样做行不通。我想要能够控制(即终止)生成的进程。工作线程或子进程将永远运行(打印/获取输入循环),因此我希望能够从主进程中杀死它们。 - Mike
2
你展示的代码应该是可以工作的;我怀疑你遇到了I/O缓冲问题。尝试使用openwrite代替。还可以尝试使用gnome-terminal -e 'sleep 36000' - zwol
显示剩余2条评论
3个回答

2

无论是 gnome-terminal 还是 xterm,都可以在终端打开后运行任意命令。

因此,我建议您编写一个辅助程序,该程序知道如何通过套接字、命名管道或其他 IPC 机制与您的主程序通信。您的线程会生成终端程序,并将其传递给您的辅助程序,在终端内部运行并通过上述 IPC 通道与线程通信。


你的线程启动终端程序,并将辅助程序传递给它。我不理解这一点。我该如何将辅助程序“传递”给终端?这是我的问题之一,我不知道在终端启动后如何与其通信。 - Mike
在命令行中:如果我没记错的话,可以使用 gnome-terminal -e helper 或者 xterm -c helper。请注意,您无法可靠地为 helper 本身提供命令行参数,也无法控制其 stdinstdout - zwol
1
实际上,它是 xterm -e helper arguments...,你可以可靠地给它参数,尽管你不能(根据定义)更改 stdin/stdout/stderr,因为它们指向终端(这就是整个重点)。 - Chris Dodd

1

libvte,特别是vte_pty_*函数,可能能够实现您想要的功能。

您提出问题的方式表明您不了解Linux(或者实际上是Unix)下的窗口和终端I/O工作原理,因此我强烈建议您阅读相关资料。可以从W. Richard Stevens的书《Unix环境高级编程》开始。


也许我不知道。我知道它们实际上是文件句柄,例如/dev/pts/X。我曾经想过,一旦打开了一个新文件,就应该很容易获取它并从中打印/读取...但似乎并不是这样。我会看看你提到的库。 - Mike
我的印象是你对终端设备的构想是错误的。打开/dev/pts/X会使你成为伪终端内部的进程,而不是从伪终端接收的进程。要成为从伪终端接收的进程,你需要打开/dev/ptmx(然后通过几个步骤设置将在其中的进程的pty)。 - zwol

0

据我理解,应用程序必须能够打印到终端 - 但您是否也希望它从终端读取?终端是否应该由用户控制?

我会使用终端的文件描述符进行操作,您应该检查终端从哪个文件获取用户输入(可能不是stdin,而是一些/dev/pts?),以及终端将其输出写入哪个文件,并且您可以捕获它,并且您还可以写入其中,导致内容在终端中显示。但要注意: 1)终端本身可能会启动shell(bash)-如果您写入/dev/pts,它将显示在终端中,但不会传递给终端中的bash进程-您无法在这种终端中远程执行命令, 2)我认为在终端启动时将创建/dev/pts/x文件,因此您无法fork + dup + exec并捕获终端输出 3)在终端中运行的进程也会打印一些输出-它将不会从/dev/pts读取

也许您需要使用C编写应用程序,该程序将仅在终端中运行,并且该应用程序将与拥有终端的应用程序通信?


感谢您的输入。请检查我对原帖的编辑。我认为这就是您所建议的吗?我已经尝试过了,但它没有在屏幕上打印出来... 有看到哪里有问题吗? - Mike
谁知道发生了什么。在我的系统上,当我只打开两个xterm实例,并在其中一个上使用echo foo > /dev/pts/1时,在第二个实例中会显示'foo'。虽然我不是Unix专家,但可能有些终端不使用/dev/pts? - Al W
有趣的是...从一个窗口直接发送命令到另一个窗口实际上可以工作,但是从C代码发送到窗口就不行... - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接