single instance

K

Knute Johnson

1) It uses a smaller unit, but does not guarantee a smaller
granularity.

At least on my version of Windows, it was much finer.
2) It is only guaranteed to work within the same program as
the base is not fixed.

3) No matter how small a granularity, then it still just reduces
the risk of concurrency problems but does not eliminate the risk.

Arne

It doesn't have to be perfect just good enough to stop what you want to
stop. For the application I have, I'm not worried about somebody
starting two copies with a batch file only by clicking on an icon or
typing into a command line. For that it will be more than adequate.
 
A

Arne Vajhøj

At least on my version of Windows, it was much finer.


It doesn't have to be perfect just good enough to stop what you want to
stop. For the application I have, I'm not worried about somebody
starting two copies with a batch file only by clicking on an icon or
typing into a command line. For that it will be more than adequate.

Sure.

But it is not a "canned package for ensuring single instance".

Arne
 
R

Roedy Green

No, it's not. If you have a UUID larger than 16 bits, then any "16-bit
shorthand" is necessarily non-unique for all possible UUIDs, and is thus a
hash code.

The 16 bit code is assigned only for a short time, then they can be
recycled for use by a different UUID. Unless a UUID is in use on a
particular machine it does not have a 16 bit assignment.

16 bits are plenty for IN USE UUIDs on one machine.

I am not suggesting UUIDs get assigned universally to a 16 bit id,
e.g. being assigned a permanent well known port number. That would
fail in minutes.
--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
R

Roedy Green

At least on my version of Windows, it was much finer.

Timer Resolution
Resolution Platform
55 ms Windows 95/98
10 ms Windows NT, Windows 2000,
Windows XP single processor
15.625 ms Windows NT, Windows 2000, Windows XP dual processor
1 or 15.625 ms Vista. 1 only if you sleep between calls to
currentTimeMillis. I kid you not.
? Windows 7.
1 ms Mac OS X
--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
R

Roedy Green

At least on my version of Windows, it was much finer.

I was able to determine it was 300 ns or less, but a ns is a pretty
short time.
--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
R

Roedy Green

Whatever you mean, it doesn't make sense for a program that has to know the
UUID to bother with a 16-bit port value also. If a UUID is involved, then
just use it. Mapping the UUID to a 16-bit value doesn't fix anything when
to get the 16-bit port value, you have to know the UUID.

Just use the UUID.

There is no need to put a pair of UUID socket numbers in every
packet. That is a waste of bits. You do want a 16 bit shorthand. Maybe
eventually a 64 bit port number, but for now such as conversion would
be considered too disruptive. What I am calling for now would just be
an optional add-on mechanism to assign a free port.

--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
R

Roedy Green

It would not be possible in the way you seem to envision it.

We are going around in circles. Would a someone else like to weigh
in?
--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
R

Roedy Green

It would not be possible in the way you seem to envision it.

What we have now works because you need only one socket number per
incoming service. All callers share the same port. So we can have 64K
incoming services, not enough for all possible services but enough for
the number currently active.

We need one socket number per outgoing connection. They can overlap
incoming service numbers. So we can have 64K outgoing connections,
plenty, for now.

Lets say I set up a port assigning service. When you a need to assign
a port for an incoming service that does not have a fixed assignment,
you send me, Roedy, an email, along with a UUID for the service. I
have a list of the ports you have already assigned. I assign a free
one, and tell you to use it for your service. I make a record of
that. When someone wants to connect to you service, then send me an
email with the UUID and the name of the machine they want to connect
to. I look the port number up in my database and tell him which port
to use.

Let's say the service provider shuts the service down and restarts it.
All works just as if would now with a well-known port.

Let's say the service provider wants never again to provide the
service. They could send me a email tell my that service UUID X is
freeing up its socket for reuse. I will do that, but only after I
have used all the other free sockets.

We need some sort of system to ensure the callers recheck the socket
with me to check every once in a while if the service has been
deleted/moved (a rare instance). If they don't notice a deletion, no
harm done. If they don't notice a move, serious harm is done.

My imaginary email service would be a demon running on each server
handing just dynamic socket assignments for that server.
--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
R

Roedy Green

I have been working on polishing Knute's code. Mostly I have been
adding informal comments and renaming to help myself understand how it
works.

I have not run it yet, but it is getting close to a test.

see
https://wush.net/svn/mindprod/com/mindprod/singleinstance/SingleInstance.java

I have added UUIDs to break the tie for equal start times.
I have added app ids so different apps can share the same port.

I have added the ability avoid several different apps.
I have added the ability to permit two apps to run, so long as they
run on different files.
--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
K

Knute Johnson

I have been working on polishing Knute's code. Mostly I have been
adding informal comments and renaming to help myself understand how it
works.

I have not run it yet, but it is getting close to a test.

see
https://wush.net/svn/mindprod/com/mindprod/singleinstance/SingleInstance.java

I have added UUIDs to break the tie for equal start times.
I have added app ids so different apps can share the same port.

I have added the ability avoid several different apps.
I have added the ability to permit two apps to run, so long as they
run on different files.

Below is what I ended up with. I'm curious about the UUID. How do you
create a time based UUID? And does it have less granularity that
currentTimeMillis?

package com.knutejohnson.classes;

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 static final int port = 35798;
private static final String addr = "228.237.246.255";

private final long myTime;
private final String name;
private final InetAddress group;
private final MulticastSocket socket;
private final String token;

private volatile boolean runFlag;
private volatile Thread thread;

public Exclusive(String name) throws IOException {
myTime = System.currentTimeMillis();

this.name = name;
if (name.indexOf(",") >= 0)
throw new IllegalArgumentException(
"Comma character not allowed in name");

group = InetAddress.getByName(addr);
socket = new MulticastSocket(port);
socket.joinGroup(group);

token = String.format("%s,%d",name,myTime);
}

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

sendToken();
}
}

public void sendToken() throws IOException {
byte[] buf = token.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 recStr = new String(dp.getData(),dp.getOffset(),
dp.getLength(),StandardCharsets.US_ASCII);
String[] arr = recStr.split(",");
// if names don't match there is nothing to do
if (!name.equals(arr[0]))
continue;
long theirTime = Long.parseLong(arr[1]);
// 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();
// 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();
}
shutdown();
// if their time is after my time, send out my time
} else if (theirTime > myTime) {
sendToken();
}
} 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 up to two seconds to see if any other copy responds
// returns true if no other copy is running.
public synchronized boolean waitFor() throws InterruptedException {
wait(2000);

return runFlag;
}

public void shutdown() {
System.exit(0);
}

public static void main(String[] args) {
try {
Exclusive e = new Exclusive("Test");
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();
}
}
}
 
R

Roedy Green

Below is what I ended up with. I'm curious about the UUID. How do you
create a time based UUID? And does it have less granularity that
currentTimeMillis?

there are specified formulas for creating UUIDs. I think one way of
rapidly generating them would be to use System.currentTimeMillis for
the high 64 bits and System.nanotime for the lower 64 bits, but I
suspect that would not be considered kosher.

Another would be to use SecureRandom to generate 16 bytes, though that
probably is not as unique as you might hope.


a UUID is not just 128 bits. It has embedded fields that tell you how
it was generated.


--
Roedy Green Canadian Mind Products http://mindprod.com
The first 90% of the code accounts for the first 90% of the development time.
The remaining 10% of the code accounts for the other 90% of the development
time.
~ Tom Cargill Ninety-ninety Law
 
L

Lew

Roedy said:
Knute Johnson wrote, quoted or indirectly quoted someone who said :

there are specified formulas for creating UUIDs. I think one way of
rapidly generating them would be to use System.currentTimeMillis for
the high 64 bits and System.nanotime for the lower 64 bits, but I
suspect that would not be considered kosher.

Another would be to use SecureRandom to generate 16 bytes, though that
probably is not as unique as you might hope.

a UUID is not just 128 bits. It has embedded fields that tell you how
it was generated.

http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html
«The layout of a variant 2 (Leach-Salz) UUID is as follows: The most significant long consists of the following unsigned fields:

0xFFFFFFFF00000000 time_low
0x00000000FFFF0000 time_mid
0x000000000000F000 version
0x0000000000000FFF time_hi
....

«For more information including algorithms used to create UUIDs, see RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace,
http://www.ietf.org/rfc/rfc4122.txt
section 4.2 "Algorithms for Creating a Time-Based UUID".»
 
K

Knute Johnson

http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html
«The layout of a variant 2 (Leach-Salz) UUID is as follows: The most significant long consists of the following unsigned fields:

0xFFFFFFFF00000000 time_low
0x00000000FFFF0000 time_mid
0x000000000000F000 version
0x0000000000000FFF time_hi
...

«For more information including algorithms used to create UUIDs, see RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace,
http://www.ietf.org/rfc/rfc4122.txt
section 4.2 "Algorithms for Creating a Time-Based UUID".»

After reading the RFC, using an UUID doesn't sound too practical for the
purposes we have been discussing. It also seems clear that with the
slow clock on a Windows system that one would need a UUID generator that
could be accessed by all interested parties. If that generator were
give two requests in short order, it would have to hold up issuing a new
UUID until the clock had sequenced to the next time.
 
A

Arne Vajhøj

there are specified formulas for creating UUIDs. I think one way of
rapidly generating them would be to use System.currentTimeMillis for
the high 64 bits and System.nanotime for the lower 64 bits, but I
suspect that would not be considered kosher.

No.

The two parts are related.

And it does not do much to protect against two doing it at the
same time.
Another would be to use SecureRandom to generate 16 bytes, though that
probably is not as unique as you might hope.

SecureRandom is probably a lot better.

To be secure the chance of getting duplicate values
if two runs it at the same time should be purely random.

But it can still not guarantee uniqueness.

Arne
 
A

Arne Vajhøj

After reading the RFC, using an UUID doesn't sound too practical for the
purposes we have been discussing. It also seems clear that with the
slow clock on a Windows system that one would need a UUID generator that
could be accessed by all interested parties. If that generator were
give two requests in short order, it would have to hold up issuing a new
UUID until the clock had sequenced to the next time.


Note that randomUUID() does not return type 2 UUID.

Arne
 
A

Arne Vajhøj

DOS also lacked multitasking.

And lacking multitasking makes the issue of multiple concurrent instances
of a single program rather moot, wouldn't you say?

Sure.

But whether the OS has a PID concept or not is a question beyond the
specific usage.

Arne
 
A

Arne Vajhøj

On 1/6/2013 7:22 PM, Twirlip of the Mists wrote:
44 PM, Twirlip of the Mists wrote:
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.
[snip]

DOS also lacked multitasking.

And lacking multitasking makes the issue of multiple concurrent instances
of a single program rather moot, wouldn't you say?

Classic ... now watch him wriggle out of that one

You mean that you could not see the irrelevancy of that??

Yuck!

Arne
 
A

Arne Vajhøj

Using your very rigid definition of "platform agnostic", you can't do
anything in a platform agnostic way, not even add two and two. Using a
*useful* definition of "platform agnostic" -- say "runs on anything that
has an ANSI-compliant C compiler for it" or "runs on anything that has a
JLS-compliant JVM for it" -- it could conceivably be another story.

ANSI C does require a PID.

And specifying it in Java can not help implement in it Java.

Arne
 

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,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top