2

So, I am able to enforce single instance of my application on Windows as follows.

[STAThread]
class method Program.Main(args: array of string);
begin
  var mutex := new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
  if mutex.WaitOne(Timespan.Zero, true) then
  begin
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.ThreadException += OnThreadException;
    lMainForm := new MainForm;
    lMainForm.ShowInTaskbar := true;
    lMainForm.Visible := false;

    Application.Run(lMainForm);
  end
  else
    MessageBox.Show("Another copy running!!!");
end;

However, running the same application on Linux under mono this code does NOT work at all. I am able to run multiple copies. I don't know if it has to do with the fact that I am starting the application on the Terminal like mono MyPro.exe. If this is the problem, do you need to pass some values before you execute the command line.

Thanks in advance,

Ken White
  • 123,280
  • 14
  • 225
  • 444
ThN
  • 3,235
  • 3
  • 57
  • 115

3 Answers3

3

You probably need to enable shared handles using MONO_ENABLE_SHM environment variable:

MONO_ENABLE_SHM=1 mono MyPro.exe
Adrian Fâciu
  • 12,414
  • 3
  • 53
  • 68
  • Adrian, I did try your suggestion and it didn't work. As I said, I had to open two different terminal to be able to start two different copies of my program. So, maybe that's why your suggestion didn't work. – ThN Nov 06 '12 at 15:45
3

You need to enable shared memory in mono as Adrian Faciu has mentioned to make your approach work, however this is not the best approach (there's a reason it's disabled by default in the first place, even if I can't remember now exactly why).

I've used two solutions in the past:

  • A file-based lock. Create a known file, write the pid into that file. At startup in your app check if the file exists, and if it exists read the pid and check if there are any running processes with that pid (so that it can recover from crashes). And delete the file upon exit (in the instance that created it in the first place). The drawback is that there is a race condition at startup if several instances are launched pretty much at the same time. You can improve this with file locking, but you may have to use P/Invokes to do the proper file locking on Linux (I'm not entirely sure the managed API would do what you'd expect).

  • A socked-based lock. Open a known port. The advantage over the above is that you don't need to do any cleanup and there are no race conditions. The drawback is that you need a fixed/known port, and some other program might happen to use that exact port at the same time.

Rolf Bjarne Kvinge
  • 19,253
  • 2
  • 42
  • 86
  • Rolf Bjarne Kvinge, I have looked at the file-based lock. However, it has a major drawback. What if you are running your program on a user account with no administrator privileges like deleting a file? Most often you are on a user account not an administrator one. After implementing the file-based lock, I ran into this issue. My program was able to create the file but couldn't delete it when it was shutdown normally. – ThN Nov 07 '12 at 13:39
  • @digitalanalog: if you need the lock to span user accounts, you need to place the file somewhere all user accounts have read/write access to (C:\System\Temp comes to mind, but there may be other/better locations). – Rolf Bjarne Kvinge Nov 07 '12 at 13:50
  • Rolf, there probably is a more straight forward way of doing this through managed code, but so far I have not discovered it yet. So, I do find file-based lock simple enough to implement. I was able to figure out why it wasn't deleting the file on my Linux System. Now it works as expected. Thanks for your help. – ThN Nov 07 '12 at 15:31
1

Adrian's solution works for me(tm). Wild guess: did you need MONO_ENABLE_SHM in both invocations?

loreb
  • 1,327
  • 1
  • 7
  • 6
  • Or if all else fails, considering "the unix way", which is to have lock files in a common directory – Earlz Nov 06 '12 at 17:00
  • loreb, I am not sure if you do need it in both but I did try on both invocations anyways. Still, it didn't work. I even thought maybe because it was all uppercase letters and try it with all lowercase letters. Again, it didn't work. I don't know if this will help shed more light on this issue but I am trying to do this on PCLinuxOS under mono. – ThN Nov 06 '12 at 17:23
  • @Earlz, that's what I am looking at now as suggested by others on forums and message board online. – ThN Nov 06 '12 at 17:24
  • Debian x86_64 here fwiw, my mutex is named "mymutex". – loreb Nov 06 '12 at 17:26
  • @Earlz, If I may ask you, how did you start your program on Linux - directly by clicking right on the executable itself or starting from the terminal. Apparently, I was screwing around with the MONO_ENABLE_SHM option on the terminal and found out that it is being recognized by mono. Because when I misspelled it, mono complied that it is unrecognized command. If that is the case, then why the program won't act as expected. Please, give me step by step instructions as to how you tested this mono option. Thanks. – ThN Nov 06 '12 at 19:20
  • @digitalanalog I have no idea on how to do this. I just suggested you use what most *nix programs do: lock files and/or PID files – Earlz Nov 06 '12 at 19:27
  • @digitalanalog (1/2) MONO_ENABLE_SHM is an environment variable which you set from the terminal: typing "MONO_ENABLE_SHM=1 mono ..." sets it for the current invocation, while "export MONO_ENABLE_SHM=1" sets it until you close the terminal. – loreb Nov 06 '12 at 22:20
  • @digitalanalog (2/2) re lock files: if you're not familiar with linux, a lock file is the same as LockFileEx() in the winapi, you choose an erbitrary file (in a directory which **must** exist) and make sure that the program right after startup locks that file or exits -- see FileStream.Lock on msdn – loreb Nov 06 '12 at 22:26
  • @loreb, Just a little bit of information. When I do start my program from the terminal, control is not relinquished back to the terminal until my program is shutdown. This is how I start my program - >MONO_ENABLE_SHM=1 mono MyPro.exe – ThN Nov 07 '12 at 14:31