Description
Description
We have 2 processes. The first one opens a file with an exclusive lock (using FileShare.None), and keeps this lock for some time. Another process starts and tries to open the same file with an exclusive lock (also using FileShare.None). And it retries to open it until it gets the exclusive lock.
Here are two small programs. First, test1 is started, then, after the lock is acquired (but before it is released), test2 is started.
using System;
using System.IO;
using System.Threading;
namespace test1
{
class Program
{
static void Main(string[] args)
{
var lockfilepath = Path.Combine(Path.GetTempPath(), "test-lock");
Console.WriteLine($"{DateTime.Now} test1 {lockfilepath}");
using(var exclusiveLock = new FileStream(lockfilepath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 1, FileOptions.DeleteOnClose)) {
Console.WriteLine($"{DateTime.Now} {lockfilepath} locked");
Thread.Sleep(10 * 1000);
Console.WriteLine($"{DateTime.Now} releasing lock");
}
Console.WriteLine($"{DateTime.Now} lock released");
}
}
}
using System;
using System.IO;
using System.Threading;
namespace test2
{
class Program
{
static void Main(string[] args)
{
var lockfilepath = Path.Combine(Path.GetTempPath(), "test-lock");
Console.WriteLine($"{DateTime.Now} test2 - {lockfilepath}");
while(true) {
try {
var exclusiveLock = new FileStream(lockfilepath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 1, FileOptions.DeleteOnClose);
break;
} catch(Exception _) {
Console.WriteLine($"{DateTime.Now} retrying");
Thread.Sleep(1000);
}
}
Console.WriteLine($"{DateTime.Now} lock acquired");
}
}
}
What we see:
The first attempt by test2 to open the file fails as expected. However, the second attempt succeeds, even though test1 still has the lock.
What we expect:
test2 should loop until test1 releases the lock.
Configuration
.NET version: 6.0.100-rc.1.21463.6
OS: Linux (distro: rocky linux 8)
Architecture: x64
Regression?
This works as expected on Windows (.NET Framework 4.8, .NET Core 3.1, .NET 6 RC1) and Linux with .NET Core 3.1.
It seems to be linked to the use of FileOptions.DeleteOnClose. Using FileOptions.None gives the expected behavior.