我试图实现一个启动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...
}
我使用此功能创建2个线程并将它们分开
鉴于上述实现,我希望可以看到2个gnome终端已登录到用户'帐户使用-i ssh选项提供的密钥。该脚本应该已经执行并等待提供root密码,同时两个执行线程在pclose()停止时等待各自的gnome-terminal返回。
相反,2个gnome-terminal打开,他们正在等待root密码。 1个线程的执行在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()
答案 0 :(得分:5)
对于你的例子,gnome-terminal
命令可能是一个糟糕的选择,我当然希望它只是 的一个例子。我不清楚你为什么不直接popen()
ssh
命令。有关gnome-terminal
之后的更多内容。
你写
鉴于上述实现,我预计会有2个gnome终端 可见,已使用键登录到“用户”帐户 提供-i ssh选项。该脚本应该已经执行 并且正在等待两个线程都提供root密码 执行已经停止在pclose()等待他们的 各自的gnome-terminal返回。
,但那不是我所期望的。调用pclose()
应首先关闭流,另一端的流程将在其标准输入上看作EOF。然后该函数将等待子进程终止,但该进程不应阻止任何尝试从其标准输入读取。我通常希望两个 pclose()
调用快速返回。
现在我发现popen()
一个提供GUI的程序非常值得怀疑,即使它与gnome-terminal
的简单一样,但我倾向于猜测gnome-terminal
是
默认情况下,所有GNOME终端共享一个进程,从而减少内存使用量。可以通过使用
--disable-factory
选项启动gnome-terminal来禁用此功能。
我确信您可以理解单进程行为可能会对希望创建和管理单独子进程的API造成严重破坏。我怀疑这是观察到两次调用行为差异的原因。
此外,您应该检查函数调用的返回值,您的示例未演示。我不确定您的popen()
和/或pclose()
是否应该发出错误信号,但我认为它很有可能。