single instance

R

Roedy Green

What is the best way to ensure only a single instance of a Java
program is running.

I have used indicator files, but they can get screwed up if the user
kills the program without going through the standard shutdown.

Ideally, net new instance would just join the one already running.
This is pure GUI, so I am not worried about adding new command line
parms.
 
A

Arne Vajhøj

What is the best way to ensure only a single instance of a Java
program is running.

I have used indicator files, but they can get screwed up if the user
kills the program without going through the standard shutdown.

1) Some platform specific native code invoked via JNI.

2) A file and if found the app prompts the user to abort or continue.

3) Using IP port.
Ideally, net new instance would just join the one already running.

????

Arne
 
R

Robert Tomsick

Arne said:
1) Some platform specific native code invoked via JNI.

2) A file and if found the app prompts the user to abort or continue.

3) Using IP port.

Ok, so first, if you're doing a JWS app, you might want to try this:
http://pscode.org/jws/api.html#sis and do as specified.

Now if that's not the case then I'd go for a combination of #2 and #3. You
can't catch all the failure modes, but you can at least eliminate the "user
loves kill -9" threat.

On launch of the first instance, your program could pick a random (high)
port and open a socket. It then writes the port number to a temporary file
at a known location.

So now, on launch, all you have to do is check for the existance of that
file. If it's not there, you start as normal, see above. If it is, you
read the port number from the file, and try to connect to that socket. If
you succeed, you assume the program's already running and whine to the user.
If you fail, you assume the program was killed prematurely, you nuke the
temp file, and proceed as normal.

Of course that doesn't cover the case where your program gets whacked and
something else starts listening on it in the meantime. You can work around
that by having your program identify itself via said socket. It also
doesn't handle the case where somebody deletes the temporary file while the
app is running. Still, I suppose it's at least something of a decent
platform-specific way of ensuring you're not allowing multiple instances of
your program.

All that said, I'd just use the typical pid file approach and assume that if
the user decides to nuke the process they get to clean up the mess.

-Rob
 
R

Roedy Green

What is the best way to ensure only a single instance of a Java
program is running.

I was expecting this to be a method in some obscure corner of the Java
API. I was bracing myself for the usual RTFM (read all docs end to
end and miss nothing).

The only technique that does not have some major drawback is the UDP
broadcast, but I don't fully understand it yet.

I have recorded your ideas in my essay at
http://mindprod.com/jgloss/singleinstance.html
 
K

Knute Johnson

As far as the sockets approach goes, you might be able to avoid the need of
dealing with a magic file or hard-coded socket port by using UDP multicast
with the SO_REUSEADDR option. This would allow your program to join to a
multicast port without interference from other programs, ensuring it's
ready to receive a UDP datagram sent on the channel from a new instance
searching for a prior existing instance.

Unfortunately, unlike the exclusive-create option available for a file,
there's no such built-in support for resolving race conditions in the
socket-based approach. Unless you are willing to go without a solution, or
are confident you can correctly design and implement a solution, you may
want to stick with the more user-driven approaches suggested.

But it's there in case you want to try. :)

Pete

I'm not sure how you could do this without establishing what group and
port your were going to use before hand. But maybe that isn't what you
were saying.

So what do you think of this implementation? I did try to start two
copies with a batch file and I could get them to fail on occasion. I
don't think it would be possible for a user to start two copies
simultaneously though.

Thanks,

knute...

import java.awt.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.nio.charset.*;
import java.util.*;
import javax.swing.*;

public class Exclusive implements Runnable {
private final long myTime;
private final MulticastSocket socket;
private final InetAddress group;
private final int port;

private volatile boolean runFlag;
private volatile Thread thread;

public Exclusive(String ipStr, String portStr) throws IOException {
myTime = System.currentTimeMillis();

group = InetAddress.getByName(ipStr);
port = Integer.parseInt(portStr);

socket = new MulticastSocket(port);
socket.joinGroup(group);
}

public void start() throws IOException {
if (thread == null || !thread.isAlive()) {
runFlag = true;
thread = new Thread(this);
thread.start();

// send out my time
String str = Long.toString(myTime);
byte[] buf = str.getBytes(StandardCharsets.US_ASCII);
DatagramPacket dp =
new DatagramPacket(buf,buf.length,group,port);
socket.send(dp);
}
}

@Override public void run() {
while (runFlag) {
try {
// receive their time
byte[] buf = new byte[64];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
socket.receive(dp);
String timeStr = new String(dp.getData(),dp.getOffset(),
dp.getLength(),StandardCharsets.US_ASCII);
long theirTime = Long.parseLong(timeStr);
// if we are seeing our own packet, do nothing
if (theirTime == myTime) {
// if their time is before my time, we need to shut down
} else if (theirTime < myTime) {
stop();
shutdownHook();
// if their time is after my time, send out my time
} else if (theirTime > myTime) {
String str = Long.toString(myTime);
buf = str.getBytes(StandardCharsets.US_ASCII);
dp = new DatagramPacket(buf,buf.length,group,port);
socket.send(dp);
}
} catch (IOException|NumberFormatException ex) {
ex.printStackTrace();
stop();
}
}
}

private void stop() {
if (thread != null && thread.isAlive()) {
runFlag = false;
if (socket != null)
socket.close();
}

// signal the waitFor() method to stop waiting
synchronized (this) {
notify();
}
}

// wait for two seconds to delay program startup until we have
// time to determine if there is another copy running.
// returns true if no other copy is running.
public synchronized boolean waitFor() throws InterruptedException {
wait(2000);

return runFlag;
}

public void shutdownHook() {
// can't use invokeLater()
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(null,
"Another Copy of this Program is Already Running",
"Start Inhibited",JOptionPane.ERROR_MESSAGE);
}
});
} catch (InterruptedException|InvocationTargetException ex) {
ex.printStackTrace();
}
}

public static void main(String[] args) {
try {
Exclusive e = new Exclusive("227.228.229.230","23222");
e.start();
if (e.waitFor())
System.out.println("no other copy running!");
else
System.out.println("another copy is running");

} catch (IOException|InterruptedException ex) {
// probably don't want to start if you get an exception either
ex.printStackTrace();
}
}
}
 
T

Twirlip of the Mists

[...]
So what do you think of this implementation? I did try to start two
copies with a batch file and I could get them to fail on occasion. I
don't think it would be possible for a user to start two copies
simultaneously though.

Oh, and it should go without saying that in a real implementation, each
program would have a way to include a unique identifier (i.e. similar to
the name one would use for a named mutex on Windows) in the transmitted
message, to insure against two completely different programs that are using
the same "exclusive" implementation from conflicting with each other.

But I'll say it anyway. :)

Why not just use the process PID as unique identifier?
It is important to keep in mind that even this approach is not 100%
reliable. UDP messages are not guaranteed delivery,

This is loopback interface we're talking about, not the wild wild internet.

In any event, the error message that was proposed isn't a very useful way
of handling the situation. I'd suggest that once the old and new instance
are in communication and agree on which is which:

- The new instance sends the old its invocation command-line, then quietly
terminates.
- The old interprets this command-line and e.g. opens named documents in
additional document windows. If those are JFrames the last one should
automatically wind up with window focus.
- If those are JInternalFrames, or there were no new documents to open, the
old instance's main/most recently active JFrame grabs window focus.

So, if you just double-click on the program somewhere, the existing
instance jumps to the front of the window stack. If you double-click on a
document associated with the program, it opens in the existing instance.
This pattern of behavior is common in native apps that don't like running
in multiple instances, and so replicating it would be best given the
principle of least astonishment.

Wagging a naughty-finger in the user's face because they double-clicked a
document file associated with an already-open application, on the other
hand, and forcing them to instead drag and drop it into the existing
instance (or, worse, switch to the existing instance to use its File Open
menu and re-browse the directory tree) would violate the same principle.
 
D

Daniel Pitts

What is the best way to ensure only a single instance of a Java
program is running.

I have used indicator files, but they can get screwed up if the user
kills the program without going through the standard shutdown.

Ideally, net new instance would just join the one already running.
This is pure GUI, so I am not worried about adding new command line
parms.
A common approach I've seen is to use an indicator file, which contains
the PID of the main process. That way you can check if that PID is
still active. This of course isn't platform independent. You could
combine the idea with others in this thread though. Check the file,
which contains a TCP port number, connect to that port number to check
if the process is still alive.

Just a thought.

I might also have my program "watch" that file, and if it disappears or
becomes modified, then shut down because I know the user is trying
something they shouldn't.
 
T

Twirlip of the Mists

You misunderstand.

I do not.
The "unique identifier" is not per-process, but rather per-program.

Then you should have just said so. Use argument 0 of the command line then
-- that should be the path of the executable. Then each install of the
application will be single-instance, but by making more than one install
the user could have multiple instances. These instances would have separate
sets of settings files, however, being from separate installs, so one of
the two big reasons for inhibiting multi-instances doesn't apply there.
(The other is user convenience -- opening a load of documents and having
them all open in the same containing window, with maybe special drag and
drop options available between them, and without as much memory use as if
each had a separate process. If the user deliberately chooses to circumvent
this for some reason, though, one should defer to the user's wishes having
provided a reasonable default for the common case of a single install.)
Even if I was talking about a unique per-process identifier, process ID
isn't really all that great, because getting the process ID requires
platform-specific code.

1. Getting argument 0 doesn't, which is what now seems like the best idea.
2. Isn't there a Process class in the Java API as of a few versions ago
that interacts with the host's job control?
Not as complicated as using platform-specific code
for the whole implementation (e.g. named mutex on Windows), but still not
platform-agnostic.

The concept of a PID is platform-agnostic -- all Unices seem to have it,
MacOS is a Unix nowadays, and newer Windowses have PIDs. It'd be surprising
if there isn't a platform-agnostic way to get at PIDs -- a POSIX call that
Windows supports, most likely.
This is loopback interface we're talking about, not the wild wild internet.

Maybe you should have kept reading, [rest deleted unread]

You will need to be more polite and less judgmental if you want me to read
more of what you have to say. You catch more flies with honey than you do
with vinegar, and repeatedly insinuating that I did various things wrong or
should have done X instead of Y or etc. constitutes vinegar. Especially
when done before a live studio audience.
 
T

Twirlip of the Mists

I might also have my program "watch" that file, and if it disappears or
becomes modified, then shut down because I know the user is trying
something they shouldn't.

I'm HIGHLY dubious of nannying your users to that extent. Unless it's very
dangerous, in some sense, to allow multi-instances (data-destroying race
conditions in important files in the install directory?), if the user takes
specific and knowledgeable action to circumvent the default behavior of
only having a single instance, the user should probably be deferred to and
the perceived problem solved in other ways (e.g. using a lightweight but
properly ACID database instead of just a file, or locking the file and
requiring separate concurrent instances use separate files or even distinct
installs altogether).

I know that if I deliberately circumvent something like that, I do so at my
own risk and buggy, even data-destroying behavior is theoretically possible
among the consequences (so I should either not do so or back up the
program's data files first).

I also know that there have been many occasions when I've been frustrated
by a program "straight-jacketing" me into being unable to do something the
programmer thought unwise or even just unnecessary, but where the
programmer clearly hadn't anticipated all the uses to which the program
might be put, especially by someone that's a hacker and not just a garden
variety end-user.

Programs are the user's tools and, as such, should empower, not limit, the
user. Whereas it can make plenty of sense to include safety features
designed to make it difficult for the user to accidentally shoot himself in
the foot, cut off his finger in the saw, or shoot his co-worker from across
the room with the nailgun, it is rarely if ever worthwhile to additionally
try to design in a "cop-in-the-box" intended to catch and "punish"
deliberate attempts to circumvent such features. If I purposely circumvent
the safety on a nailgun, I do so at my own risk and probably because a
burglar broke into the shop and I need a makeshift weapon for self-defense
in a hurry, rather than because I'm an irresponsible idiot, and if I *am*
an irresponsible idiot, I'll probably find some other way to shoot myself
or my co-worker no matter how idiot-proof you try to make the nailgun.

Disclaiming all warranty and liability in the event of such tampering is
the furthest it's generally reasonable to take matters -- and, of course,
software makers are already in the habit of blanket disclaiming ALL
liability, even for actual defects in workmanship!

So I'd suggest that instead of monitoring the file for deletion or
tampering you just name it something cutesy like "DELETING ME VOIDS
WARRANTY AND MAY CAUSE MALFUNCTION.txt". :)

Nah, probably not even that, since if the program hangs and has to be
force-quit, then won't restart properly because of a stale lockfile, your
support forums will end up chock full of long threads going

Q: It hung, I end-tasked it, and it wont restart!
A: Delete the lockfile and try restarting it again.
Q: What's the "lockfile"?
A: It's the file called "DELETING ME VOIDS WARRANTY..."
Q: But I don't want to void my warranty and maybe cause even more bugs!
A: The name's a joke. There's no warranty anyway and deleting it won't
cause a malfunction if the program isn't currently running.
Q: Are you sure?
A: Yes.
Q: Are you really, REALLY sure?
A: Yes!
Q: It won't void the warranty on my *computer itself* will it?
A: It didn't come with the computer, so, no, it can't.
Q: Hmm. It still doesn't seem like a good idea. I think I'll get a second
opinion. <starts new thread on the same topic>
A: <bangs head against wall>
 
T

Twirlip of the Mists

Correct: test C code written and checked to prove your point. The Stratus
VOS OS left the file in place: you could see it from list_directory after
it had been deleted, but Linux doesn't do that.

However, the automatic cleanup is easy enough to manage from C via the
atexit() function, which is very to use since you just call atexit() near
the start of the main() function: once atexit() has registered your exit
action(s) you get on with whatever the program is meant to do in the
knowledge that these actions will happen regardless of how the program
exits (power failures and system crashes excluded).

In other words, atexit is a fine way to implement this if you're happy with
a solution that fails and leaves a stale lock every time there's a
thunderstorm. :)
It looks as though the nearest we can come to this in Java is via
try...finally blocks.

However, I'm wondering if the finally block would always execute, e.g. if
the try...finally block is in the main() method of a program that exits
leaving thread(s) running to do the work, does the finally block still
get still run when the last thread(s) terminates? I had a fairly cursory
look at JLS 14.20.1 but it wasn't clear on this point.

The finally will execute when the main method exits, which, in a GUI
program, is probably long *before* the app terminates. It won't execute at
all in a console app that ends via System.exit(0) or similar without
falling off the end of main. It will execute if it falls off the end of
main however.

Java has Runtime.getRuntime().addShutdownHook(Thread x), which *will* run
on System.exit(0) and *won't* run immediately if the startup thread of a
GUI app falls off the end of main.

However, both a main finally block and addShutdownHook are vulnerable to
the aforementioned thunderstorm, and, additionally, to all of the
following:

* VM crash
* Crash (e.g. segfault) in native method
* kill -9, force-quit, Task Manager End Task, and equivalents

C's atexit is probably vulnerable to the latter two, mitigatable only
partially by registering signal handlers.

The only thing I can think of that even the thunderstorm won't **** up is
an active system where the lockfile is only considered valid if some
associated "heartbeat" is still going, so, the lockfile invalidates on a
deadman switch even if not deleted. An associated pulse you can test for on
a loopback port was already suggested elsewhere in this thread. Having the
lockfile contents be a representation of a time, updated by the live
application every 1 second, and treated as invalid if it's stale by at
least 5 seconds, is another possibility -- a fresh instance can simply
overwrite the file and carry on if it's older than 5 seconds, and otherwise
wait (5 - file's age at time of startup-attempt) seconds to see if the file
changes, then do whatever's appropriate based on whether it did or not. (On
Unix, at least, you can just "touch" the file to "heartbeat" and test its
modification time to "take a pulse".)
 
A

Arne Vajhøj

However, the automatic cleanup is easy enough to manage from C via the
atexit() function, which is very to use since you just call atexit() near
the start of the main() function: once atexit() has registered your exit
action(s) you get on with whatever the program is meant to do in the
knowledge that these actions will happen regardless of how the program
exits (power failures and system crashes excluded).

Unfortunately those may be a pretty big part of the actual
problems encountered in the real world.

We have been talking a lot about killing the process, but the
above two seems much more likely to me.
It looks as though the nearest we can come to this in Java is via
try...finally blocks.

To me Runtime addShutdownHook sounds closer in functionality.
However, I'm wondering if the finally block would always execute, e.g. if
the try...finally block is in the main() method of a program that exits
leaving thread(s) running to do the work, does the finally block still
get still run when the last thread(s) terminates? I had a fairly cursory
look at JLS 14.20.1 but it wasn't clear on this point.

http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html

says:

Note: If the JVM exits while the try or catch code is being executed,
then the finally block may not execute. Likewise, if the thread
executing the try or catch code is interrupted or killed, the finally
block may not execute even though the application as a whole continues.

and:

public class ExitFinally {
public static void main(String[] args) {
try {
System.exit(0);
} finally {
System.out.println("final");
}
}
}

does not print anything.

So I think the answer is NO.

Arne
 
A

Arne Vajhøj

I do not.

Obviously you did.
Then you should have just said so.

He did.

<quote>
Oh, and it should go without saying that in a real implementation, each
program would have a way to include a unique identifier (i.e. similar to
the name one would use for a named mutex on Windows) in the transmitted
message, to insure against two completely different programs that are using
the same "exclusive" implementation from conflicting with each
other.</quote>

"... each program would have a way to include a unique identifier ...
to insure against two completely different programs ... conflicting
with each other"

Count the frequency of "program" and "process".
The concept of a PID is platform-agnostic -- all Unices seem to have it,
MacOS is a Unix nowadays, and newer Windowses have PIDs. It'd be surprising
if there isn't a platform-agnostic way to get at PIDs -- a POSIX call that
Windows supports, most likely.

*nix and Windows support does not mean platform-agnostic.
It is important to keep in mind that even this approach is not 100%
reliable. UDP messages are not guaranteed delivery,

This is loopback interface we're talking about, not the wild wild internet.

Maybe you should have kept reading, [rest deleted unread]

You will need to be more polite and less judgmental if you want me to read
more of what you have to say.

Peter most likely does not care whether you read his posts or not.

Arne
 
R

Roedy Green

I don't think any of these approaches are immune to system crashes, but
should be good enough to prevent single processes, whether launched by a
user or automatically by the system, from running more copies that are
wanted.

With windows perhaps you start a small service on every boot. When it
starts, it can presume nothing is running. You could even interrogate
at the command line it if is safe to start a new instance, rather than
loading it and discovering only after it had started execution it
should die..

One feature of this system is you want it to check as early as
possible in the load process if there is another instance.

The other is a way of passing command line parms of a second instance
to the first in some uniform way.

It might be nice if the mechanism worked for code in any language.
 
A

Arne Vajhøj

I was expecting this to be a method in some obscure corner of the Java
API. I was bracing myself for the usual RTFM (read all docs end to
end and miss nothing).

The only technique that does not have some major drawback is the UDP
broadcast, but I don't fully understand it yet.

I have recorded your ideas in my essay at
http://mindprod.com/jgloss/singleinstance.html

<quote>
Test for the presence of a busy.marker file. If one exists, abort. If
not create one. The test and create can be in the bat file that triggers
the app or in the app itself
</quote>

Who can see a concurrency problem in that logic?

<quote>
// if we are seeing our own packet, do nothing
if ( theirTime == myTime )
{
</quote>

Who can see a concurrency problem in that logic?

<quote>
public void shutdownHook()
{
// can't use invokeLater()
try
{
EventQueue.invokeAndWait( new Runnable()
{
public void run()
{
JOptionPane.showMessageDialog( null,
"Another Copy of this Program is Already Running",
"Start Inhibited", JOptionPane.ERROR_MESSAGE );
</quote>

who thinks this conflicts with the Java docs for addShutdownHook
that states:

"Attempts to use other thread-based services such as the AWT
event-dispatch thread, for example, may lead to deadlocks."

Arne
 
K

Knute Johnson

On 1/3/2013 10:12 AM, Roedy Green wrote:
<quote>
// if we are seeing our own packet, do nothing
if ( theirTime == myTime )
{
</quote>

Who can see a concurrency problem in that logic?

The risk is, that in Windows anyway, where the system clock granularity
is 17ms it is possible to start two copies of a program with a batch
file and have them both have the same start time. The risk of doing
that by hand (which is what I really want to protect against) is, I
think, infinitesimal.
<quote>
public void shutdownHook()
{
// can't use invokeLater()
try
{
EventQueue.invokeAndWait( new Runnable()
{
public void run()
{
JOptionPane.showMessageDialog( null,
"Another Copy of this Program is Already Running",
"Start Inhibited", JOptionPane.ERROR_MESSAGE );
</quote>

who thinks this conflicts with the Java docs for addShutdownHook
that states:

"Attempts to use other thread-based services such as the AWT
event-dispatch thread, for example, may lead to deadlocks."

Arne

Bad choice of names for my method. It did seem logical when I thought
it up though. It was not my intent however to have this method called
from Runtime.shutdownHook(). I don't think I knew this method existed.
 
A

Arne Vajhøj

The risk is, that in Windows anyway, where the system clock granularity
is 17ms it is possible to start two copies of a program with a batch
file and have them both have the same start time. The risk of doing
that by hand (which is what I really want to protect against) is, I
think, infinitesimal.

Many concurrency problems are not very likely.

A lot of people initialized a JFrame based GUI on the main
thread for years without problems.
Bad choice of names for my method. It did seem logical when I thought
it up though. It was not my intent however to have this method called
from Runtime.shutdownHook(). I don't think I knew this method existed.

Ah.

My mistake.

I assumed based on the name.

Assumptions are the mother of all f......!

Arne
 
A

Arne Vajhøj

Many concurrency problems are not very likely.

A lot of people initialized a JFrame based GUI on the main
thread for years without problems.

And just to be clear: the code may be perfectly fine for your
specific purpose - I am concerned because Roedy is selling it as
a general solution when it do have a concurrency problem.

Arne
 
L

Lew

Exactly what makes them so pernicious to fix.

That kind of thinking in software engineering has actually killed people.
Horridly and painfully.

On single-core CPUs, which are no longer so common, threading issues were
masked. They became evident to the point where Sun had to change the
instructions not only about initialization but construction, once multi-core
mobos became common some years ago. They even had to overhaul the entire
concurrency memory model. So "years without problems" is an utterly specious
argument.
And just to be clear: the code may be perfectly fine for your
specific purpose - I am concerned because Roedy is selling it as
a general solution when it do have a concurrency problem.

It may be fine for your specific purpose, but if it has a concurrency bug
wired in I would not bet on it.

The point in software engineering is *not* to design for the "maybe there
won't be a problem this time" scenario.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top