我正在尝试实现一个工具,该工具启动2个ssh连接并执行一个需要root权限的脚本。
下面是一个非常简单的实现:
void* SshConnection(void* args)
{
char buffer[5000];
FILE* popenReturn = NULL;
//get the hostname to connect to
const char* hostname = (const char*)args;
snprintf(buffer, sizeof(buffer),
"/usr/bin/gnome-terminal -x bash -c \""
"ssh -t user@%s "
"-i /home/user/.ssh/key.key "
"\\\"/home/user/DoRootThings.bash\\\" ",hostname);
popenReturn = popen(buffer,"w");
pclose(popenReturn);
//...connect to the host again later on and look at results of DoRootThings.bash...
}我使用这个函数创建了两个线程,并将它们分开。
考虑到上面的实现,我希望使用-i ssh选项提供的键登录到“用户”帐户的2个gnome终端是可见的。脚本应该已经执行,并且正在等待提供根密码,而两个执行线程都在pclose()处停止执行,同时等待各自的gnome终端返回。
相反,两个gnome终端会打开,它们正在等待根密码。其中一个线程的执行在pclose()处停止,而其他线程pclose()则立即返回。然后这个线程继续查看DoRootThings.bash的结果,没有任何结果,因为它仍然在等待密码的执行!
popen()和pclose()的Solaris手册页声称它们都是线程安全的。为了安全起见,我尝试过多种形式的锁定,但都没有用。
唯一有效的锁定形式是
pthread_lock(&lock1);
popenReturn = popen(buffer,"w");
pclose(popenReturn);
pthread_unlock(&lock1);但这给我留下了一个单一的解决方案。
这是否是手册页出错,而popen()和pclose()线程不安全的情况?如果是这样的话,是否有一个锁定解决方案来解决这个问题?
否则,我在执行过程中难道没有做正确的事情吗?
注意:我最初使用的是system(),而不是popen()和pclose(),但这不是线程安全调用,而system()的Solaris手册页则使用了popen()和pclose()。
发布于 2018-01-09 00:23:50
对于您的示例来说,gnome-terminal命令可能是一个糟糕的选择,我当然希望它只是一个示例。我不清楚为什么您不直接使用popen()命令ssh。稍后将更多地介绍gnome-terminal。
你写
考虑到上面的实现,我希望使用-i ssh选项提供的键登录到“用户”帐户的2个gnome终端是可见的。脚本应该已经执行,并且正在等待提供根密码,而两个执行线程都在pclose()处停止执行,同时等待各自的gnome终端返回。
但这不是我所期望的。调用pclose()应该先关闭流,另一端的进程将在其标准输入上将其视为EOF。然后,该函数将等待子进程终止,但该进程不应阻止从其标准输入读取的任何尝试。我通常希望两个pclose()调用都能快速返回。
现在,我发现popen()是一个非常值得怀疑的程序,它提供了一个图形用户界面,甚至像gnome-terminal的程序一样简单,但是我倾向于猜测gnome-terminal是特别棘手的,因为事实上
默认情况下,所有GNOME终端共享一个进程,从而减少内存使用。可以通过使用
--disable-factory选项启动gnome终端来禁用此功能。
我相信您可以理解,单进程行为很可能会破坏期望创建和管理独立子进程的API。我怀疑这就是这两个电话在行为上观察到的差异的原因。
此外,您应该检查函数调用的返回值,您的示例没有演示这些值。我不确定您的popen()和/或pclose()是否存在信令错误,但我认为这是一个很好的可能性。
https://stackoverflow.com/questions/48159534
复制相似问题