我有一个可能在许多进程中共享的资源,需要在不再使用时进行清理。
C#中最简单的方法是保持跨进程的使用次数,以便在不再使用资源时可以清理资源?
(如果使用资源的最后一个进程终止,只要下次使用的资源具有有效的使用计数,就可以让资源不同意。)
答案 0 :(得分:2)
您正在描述在.net远程处理中实现的模式,其中资源的使用者可能位于不同的计算机上。这可以通过强制消费者明确释放对象,使用终身租约进行备份,如果消费者没有刷新租约,则会自动将消费者计时。
鉴于所有这些已经在.net框架中,我建议使用远程处理来生成框架。
答案 1 :(得分:1)
如果所有进程都在同一台机器上,我将创建一个包含实例计数的文件。当资源由进程供应时,应该打开文件进行写入,从而有效地锁定文件。应读取并递增实例计数,然后在文件上释放写锁定。
当进程退出(或完成资源)时,获取对文件的写锁定并减少资源计数。如果在减量后资源计数为零,则启动清理过程。
如果第二个进程尝试在共享文件上获取写锁定而文件已经打开以供另一个进程写入,则必须具有重试逻辑。
重要的一点是操作系统可以为您提供独占的写锁定,这实际上是您的关键部分。
答案 2 :(得分:0)
我使用的代码:
internal sealed class InterProcessResource {
private static readonly string MutexNameThisProcess = "IPR-" + Guid.NewGuid().ToString();
private static readonly Mutex MutexThisProcess = new Mutex(true, MutexNameThisProcess);
private readonly MemoryMappedFile mmf;
private readonly string mutexName;
public InterProcessResource(string resourceName) {
this.mutexName = resourceName + "-mtx";
this.mmf = MemoryMappedFile.CreateOrOpen(resourceName + "-mmf", 16 * 1024, MemoryMappedFileAccess.ReadWrite);
}
public void Acquire(Action initAction) {
using (new Mutex(true, this.mutexName)) {
var currentList = ReadStringList(mmf);
if (currentList.Count == 0) {
initAction();
}
var newList = PruneMutexList(currentList);
newList.Add(MutexNameThisProcess);
WriteStringList(this.mmf, newList);
}
}
public void Release(Action freeAction) {
using (new Mutex(true, this.mutexName)) {
var currentList = ReadStringList(this.mmf);
var newList = PruneMutexList(currentList);
WriteStringList(this.mmf, newList);
if (newList.Count == 0) {
freeAction();
}
}
}
private static List<string> ReadStringList(MemoryMappedFile mmf) {
var list = new List<string>();
using (var stream = mmf.CreateViewStream()) {
var reader = new BinaryReader(stream);
int count = reader.ReadInt32();
for (int i = 0; i < count; i++) {
list.Add(reader.ReadString());
}
}
return list;
}
private static void WriteStringList(MemoryMappedFile mmf, List<string> newList) {
using (var stream = mmf.CreateViewStream()) {
var writer = new BinaryWriter(stream);
int count = newList.Count;
writer.Write(count);
for (int i = 0; i < count; i++) {
writer.Write(newList[i]);
}
}
}
// removes our mutex name AND any dead processes mutex names
private static List<string> PruneMutexList(List<string> list) {
var newList = new List<string>();
foreach (var s in list) {
if (s != MutexNameThisProcess) {
Mutex m;
if (Mutex.TryOpenExisting(s, out m)) {
newList.Add(s);
m.Dispose();
}
}
}
return newList;
}
}