Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Named mutex not working on Linux and MacOS when AOT compiling #110348

Open
darind opened this issue Dec 3, 2024 · 7 comments
Open

Named mutex not working on Linux and MacOS when AOT compiling #110348

darind opened this issue Dec 3, 2024 · 7 comments

Comments

@darind
Copy link

darind commented Dec 3, 2024

Description

Acquiring a global named mutex doesn't seem to work on MacOS and Linux when the application is compiled with NativeAOT.

Reproduction Steps

internal static class Program
{
    private static void Main(string[] args)
    {
        using (var mutex = new Mutex(false, "Global\\{604074dc-be47-4a35-b79d-b79eead0c022}"))
        {
            mutex.WaitOne();

            Console.WriteLine("The app is now running...");
            Console.ReadLine();
        }
    }
}

Compile to native using the following:

dotnet publish --configuration Release --runtime osx-x64 --output dist

Expected behavior

The second instance of the program blocks and waits until the first has terminated

Actual behavior

The second instance successfully acquires the mutex.

Regression?

No response

Known Workarounds

No response

Configuration

  • .net 8
  • MacOS and Linux (ubuntu 24)
  • x64

Other information

The same works if the application is not compiled to native code but simply build in release mode:

dotnet build --configuration Release
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Dec 3, 2024
Copy link
Contributor

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

@MichalStrehovsky
Copy link
Member

I think this is #48720. Native AOT uses the managed Mutex implementation, not the one in CoreCLR PAL.

@darinkes
Copy link

What's the state of this issue?
Are there any known workarounds?

Just tried .net 9 and Mutex still doesn't work as expected if compiled with AOT.

BobLd added a commit to CalyPdf/Caly that referenced this issue Feb 23, 2025
BobLd added a commit to CalyPdf/Caly that referenced this issue Feb 23, 2025
BobLd added a commit to CalyPdf/Caly that referenced this issue Feb 23, 2025
BobLd added a commit to CalyPdf/Caly that referenced this issue Feb 23, 2025
BobLd added a commit to CalyPdf/Caly that referenced this issue Feb 23, 2025
@kouvel kouvel removed the untriaged New issue has not been triaged by the area owner label Feb 25, 2025
@kouvel kouvel modified the milestones: 10.0.0, Future Feb 25, 2025
@kouvel
Copy link
Member

kouvel commented Feb 25, 2025

The implementation used by NativeAOT currently just uses in-process mutexes and doesn't support cross-process synchronization. Fixing that would be good and is under consideration.

If you're using a named mutex to limit an application to one instance, an alternative may be to use the file system. Does your scenario need some of the other functionality of mutexes?

@scgm0
Copy link

scgm0 commented Mar 5, 2025

The implementation used by NativeAOT currently just uses in-process mutexes and doesn't support cross-process synchronization. Fixing that would be good and is under consideration.

If you're using a named mutex to limit an application to one instance, an alternative may be to use the file system. Does your scenario need some of the other functionality of mutexes?

The issue with using the file system is that if the application crashes, it can lead to a deadlock until the user manually deletes the file...
Some cross-platform details in dotnet always present problems, such as cross-platform compilation with Native AOT, global mutexes, and so on...

@darinkes
Copy link

darinkes commented Mar 5, 2025

@scgm0 this works for me on Linux, Mac and Windows:

            try
            {
                _lockFile = File.Open(LockFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
            }
            catch (Exception e)
            {
                Log.Information("Another Instance is already Running");
                Environment.Exit(1);
            }

If the application crashes and the lockfile doesn't get removed, the exclusive lock can be acquired on restart.

@scgm0
Copy link

scgm0 commented Mar 5, 2025

@scgm0 this works for me on Linux, Mac and Windows:

        try
        {
            _lockFile = File.Open(LockFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
        }
        catch (Exception e)
        {
            Log.Information("Another Instance is already Running");
            Environment.Exit(1);
        }

If the application crashes and the lockfile doesn't get removed, the exclusive lock can be acquired on restart.

Thanks for the approach! I'll see if it's available later

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants