问题
I'm trying to implement a tool that starts 2 ssh connections and executes a script that requires root permission.
Here is a very simple implementation:
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 create 2 threads using this function and detach them
Given the above implementation I would expect 2 gnome-terminals to be visible that have logged into the 'user' account using they keys provided with the -i ssh option. The script should have been executed and is waiting for the root password to be provided while both threads of execution have stopped at pclose() while waiting for their respective gnome-terminals to return.
Instead, 2 gnome-terminals do open and they are waiting for the root password. The execution for 1 of the threads stops at the pclose() while the other threads pclose() immediately returns. This thread then continues onto look at the results of DoRootThings.bash without there being any results since it is still waiting for the password to execute!
Solaris man page for popen() and pclose() claims that they are both thread safe. I have tried multiple forms of locking just to be safe to no avail.
The only form of locking that works is
pthread_lock(&lock1);
popenReturn = popen(buffer,"w");
pclose(popenReturn);
pthread_unlock(&lock1);
but this leaves me with a single threaded solution.
Is this a case of the man page being wrong and popen() and pclose() are not thread safe? If so, is there a locking solution that will fix this?
otherwise, am I not doing something correct in my implementation?
NOTE: I initially used system() instead of popen() and pclose() but this is not a thread safe call and the Solaris man page for system() reccomends popen() and pclose()
回答1:
The gnome-terminal
command is probably a poor choice for your example, and I certainly hope it's just an example. It's unclear to me why you're not popen()
ing the ssh
command directly. More on gnome-terminal
later.
You write
Given the above implementation I would expect 2 gnome-terminals to be visible that have logged into the 'user' account using they keys provided with the -i ssh option. The script should have been executed and is waiting for the root password to be provided while both threads of execution have stopped at pclose() while waiting for their respective gnome-terminals to return.
, but that's not what I would expect. Calling pclose()
should first-off close the stream, which the process on the other end will see as EOF on its standard input. The function will then wait for the child process terminate, but that process should not block on any attempts to read from its standard input. I would normally expect both pclose()
calls to return quickly.
Now I find it highly questionable to popen()
a program that presents a GUI, even as simple of one as gnome-terminal
's, but I'm inclined to guess that gnome-terminal
is especially tricky on account of the fact that
By default, all GNOME terminals share a single process, reducing memory usage. This can be disabled by starting gnome-terminal with the
--disable-factory
option.
(gnome-terminal manual page)
I'm sure you can appreciate that that single-process behavior is likely to play havoc with an API that expects to create and manage separate child processes. I suspect that this is the reason for the observed difference in the behavior of the two calls.
Furthermore, you should check the return values of your function calls, which your example does not demonstrate. I'm not certain that your popen()
and / or pclose()
should be signaling errors, but I'd rate it a good possibility.
来源:https://stackoverflow.com/questions/48159534/pclose-prematurely-returning-in-a-multi-threaded-environment-solaris-11