Allowing only one instance of a program

BlitzMax Forums/BlitzMax Programming/Allowing only one instance of a program

Chapman7(Posted 2014) [#1]
So I want only one instance of a game running. If another game starts while one is running, I want it to notify the user and close.

Another thread said to create a Mutex to do it. I am wondering:

1. Are there are any disadvantages (memory, performance, etc)
2. Since I would be using BRL.Threads, do I have to compile with MultiThreading enabled?
2.a. If so, are there any computers that wouldn't be able to run a multithreaded app?
3. Are there any better methods?


xlsior(Posted 2014) [#2]
There's an easier quick-and-dirty method as well:

retrieve a list of the running processes, and if you see more than one entry with the same name as the name of the running program ( appArgs[0] ), you know you launched more than one copy and it can notify & terminate itself.

(Caveat there is that if the user renames the program he/she can run a 2nd copy)

As far as multithreading is concerned: Any computer can run multi-threaded apps, although you wouldn't see much of a performance increase on a computer with single-core processor.

(As a matter of fact: Since the mult-threaded garbage collector is less efficient than the default single-threaded one that blitzmax uses, you may see decreased performance even on multi-core processors, depending on your program design and what the individual threads are actually doing)


Chapman7(Posted 2014) [#3]
Thanks for the reply! If I had a game named GAMEX and someone decided to make a program also called GAMEX and they ran it before running my game, does it stop my game from opening?


xlsior(Posted 2014) [#4]
I guess it wouldn't see the difference, unless you did some further digging around with the windows API to retrieve the path of the executable, and see if that matches too...

Anyway, here's some code I found floating around on my Pc that displays the list of running processes under Windows:




Derron(Posted 2014) [#5]
The very "easiest" way:

- On start of your app check if "bla.lock" exists in the apps directory (or a user dir)
- If yes: exit app
- If not: create a "bla.lock" file in your apps/user directory and run the app as normal


This is the way Thunderbird and others work too.


bye
Ron


Chapman7(Posted 2014) [#6]
Thanks for the replies guys!

Derron, I saw that method in another post and thought it sounded pretty good. What would happen though if the application crashes?


Derron(Posted 2014) [#7]
Then you have to manually remove that file (this is what you have to do with Thunderbird too - or with Geany on Linux).

Another way is to combine things: check for process names + lock file.

Another option is: do not let your app crash :D. If one "kills" your app (task manager) it is their fault.

I do not know how this can be done: but your app could open a file handle to a file "exclusively" - so no other app is able to work with this file. As soon as your app is no longer running, this handle is not existing anylonger, other apps can work with the file again. Means: as long as your app is running, no second instance of your app can get a handle to a specific file (eg. the lock file).


bye
Ron


xlsior(Posted 2014) [#8]
Another option is: do not let your app crash :D. If one "kills" your app (task manager) it is their fault.


Unexpected reboots, loss off power, BSOD, ...

There's a TON of other unexpected restarts that aren't explicitly initiated by the user.

But a combination may not be a bad idea:

Another way is to combine things: check for process names + lock file.


When launching the program: If you SEE the lock file but NOT the process in the process list, it's likely a left-over from a previous crash...

If you DON'T see a lock file but DO see the process, it could be another program/game with the same executable name..

But I guess it kind of depends on what you are hoping to accomplish: If this just an easy "don't want to user to launch a dozen processes that take up unnecessary resources", so I'm saving them from themselves", or is this an "I don't want users to cheat by playing multiple characters at the same time in windowed mode from one computer to keep things fair to other network players"

The difference here: Are you expecting the user to actively circumvent your protections, or is there little for them to gain by running multiple instances?

(Keep in mind: They can always install a second copy in a different folder to circumvent most of these kind of checks, especially if they give the executable a different name)


Derron(Posted 2014) [#9]
As soon as you place your lock file in a windows folder all "copies" will find this lock file... similar to the BlitzMax demo creating a suspicious file within windows/system32 to track the time left for the demo - it does not matter where you store your demo, it always knows when it was first started...

... but this is also because Mark used multiple approaches: file + Registry (both store a specific value). Means: another option is to store things in the Registry instead of a file (but the file has this exclusive file handler option).


bye
Ron


Brucey(Posted 2014) [#10]
As Derron says, you open the file with a lock on it, if locking the file fails, then another program must already be started with a lock on the file.
If the program crashes the lock is freed - as the process no longer exists.

A shared memory lock is another possibility - on Windows, I believe this uses a file, and on *nix, the system shared memory area.


bonito(Posted 2014) [#11]
You might use a MS-Windows Mutex which can be named and is than visible for all processes. Using those has no problems with BSODs, reboots etc.
I use such in other projects but I have no wrap-code for BMax at hand yet.


xlsior(Posted 2014) [#12]
Here's another example, using shared memory:



If you activate some shared memory, you can store a string there indicating the program is running. When you launch a second instance, it can see the shared memory and determine the other copy is running.

I'd assume the shared memory would reset on reboot if the application gets terminated unexpectedly...


Grisu(Posted 2014) [#13]
Hello everyone.
Does the code above work under Linux and Mac as well?


xlsior(Posted 2014) [#14]
the shared memory sample above is Windows only


Derron(Posted 2014) [#15]
For Linux there are some equivalents like

"mmap":
http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html

or
"shmget":
http://linux.die.net/man/2/shmget


Dunno, what's up on Mac.


bye
Ron


dw817(Posted 2016) [#16]
Ow, I see what I did, I answered to the wrong thread. Sorry 'bout that.

Still, Chapman. If you are here around, you can find the solution to your question, I answered near the bottom HERE:

http://www.blitzbasic.com/Community/posts.php?topic=105216